From 71b913d7fe8ce5bea7f84ae2b3ce969be09b238d Mon Sep 17 00:00:00 2001 From: Robert Helewka Date: Thu, 23 Jul 2026 12:04:37 -0400 Subject: [PATCH] CX Discovery Notebook --- cxxm.md | 453 + .../ctm_business_case_no_current_state.ipynb | 3217 ++--- .../ctm_business_case_virtual_agents.ipynb | 679 +- studies/202607_CX_AI_Diagnostic/README.md | 74 + studies/202607_CX_AI_Diagnostic/config.toml | 73 + .../202607_CX_AI_Diagnostic/configs/base.yaml | 184 + .../configs/contact_center.yaml | 62 + .../configs/financial_services.yaml | 14 + .../diaglib/__init__.py | 62 + .../202607_CX_AI_Diagnostic/diaglib/config.py | 77 + .../202607_CX_AI_Diagnostic/diaglib/export.py | 62 + .../202607_CX_AI_Diagnostic/diaglib/models.py | 281 + .../diaglib/scoring.py | 133 + .../diaglib/staging.py | 29 + .../diaglib/value_math.py | 228 + .../diaglib/visuals.py | 208 + .../docs/build_spec_v1.md | 111 + .../202607_CX_AI_Diagnostic/exports/.gitkeep | 0 .../notebooks/diagnostic.ipynb | 10520 ++++++++++++++++ .../202607_CX_AI_Diagnostic/pyproject.toml | 38 + .../scripts/build_notebook.py | 630 + .../scripts/export_report.py | 47 + .../202607_CX_AI_Diagnostic/tests/conftest.py | 70 + .../tests/test_config.py | 73 + .../tests/test_export.py | 52 + .../tests/test_scoring.py | 85 + .../tests/test_staging.py | 15 + .../tests/test_value_math.py | 145 + .../202607_CX_Discovery_Workshop/README.md | 83 + .../202607_CX_Discovery_Workshop/config.toml | 73 + .../discoverylib/__init__.py | 62 + .../discoverylib/session.py | 251 + .../discoverylib/staging.py | 29 + .../discoverylib/topics.py | 428 + .../docs/board_preview.png | Bin 0 -> 100121 bytes .../docs/cx_discovery_survey.md | 453 + .../exports/.gitkeep | 0 .../notebooks/cx_discovery.ipynb | 5353 ++++++++ .../pyproject.toml | 35 + .../scripts/build_notebook.py | 362 + .../scripts/export_report.py | 48 + .../tests/conftest.py | 7 + .../tests/test_session.py | 117 + .../tests/test_staging.py | 15 + .../tests/test_topics.py | 62 + 45 files changed, 23170 insertions(+), 1830 deletions(-) create mode 100644 cxxm.md create mode 100644 studies/202607_CX_AI_Diagnostic/README.md create mode 100644 studies/202607_CX_AI_Diagnostic/config.toml create mode 100644 studies/202607_CX_AI_Diagnostic/configs/base.yaml create mode 100644 studies/202607_CX_AI_Diagnostic/configs/contact_center.yaml create mode 100644 studies/202607_CX_AI_Diagnostic/configs/financial_services.yaml create mode 100644 studies/202607_CX_AI_Diagnostic/diaglib/__init__.py create mode 100644 studies/202607_CX_AI_Diagnostic/diaglib/config.py create mode 100644 studies/202607_CX_AI_Diagnostic/diaglib/export.py create mode 100644 studies/202607_CX_AI_Diagnostic/diaglib/models.py create mode 100644 studies/202607_CX_AI_Diagnostic/diaglib/scoring.py create mode 100644 studies/202607_CX_AI_Diagnostic/diaglib/staging.py create mode 100644 studies/202607_CX_AI_Diagnostic/diaglib/value_math.py create mode 100644 studies/202607_CX_AI_Diagnostic/diaglib/visuals.py create mode 100644 studies/202607_CX_AI_Diagnostic/docs/build_spec_v1.md create mode 100644 studies/202607_CX_AI_Diagnostic/exports/.gitkeep create mode 100644 studies/202607_CX_AI_Diagnostic/notebooks/diagnostic.ipynb create mode 100644 studies/202607_CX_AI_Diagnostic/pyproject.toml create mode 100644 studies/202607_CX_AI_Diagnostic/scripts/build_notebook.py create mode 100644 studies/202607_CX_AI_Diagnostic/scripts/export_report.py create mode 100644 studies/202607_CX_AI_Diagnostic/tests/conftest.py create mode 100644 studies/202607_CX_AI_Diagnostic/tests/test_config.py create mode 100644 studies/202607_CX_AI_Diagnostic/tests/test_export.py create mode 100644 studies/202607_CX_AI_Diagnostic/tests/test_scoring.py create mode 100644 studies/202607_CX_AI_Diagnostic/tests/test_staging.py create mode 100644 studies/202607_CX_AI_Diagnostic/tests/test_value_math.py create mode 100644 studies/202607_CX_Discovery_Workshop/README.md create mode 100644 studies/202607_CX_Discovery_Workshop/config.toml create mode 100644 studies/202607_CX_Discovery_Workshop/discoverylib/__init__.py create mode 100644 studies/202607_CX_Discovery_Workshop/discoverylib/session.py create mode 100644 studies/202607_CX_Discovery_Workshop/discoverylib/staging.py create mode 100644 studies/202607_CX_Discovery_Workshop/discoverylib/topics.py create mode 100644 studies/202607_CX_Discovery_Workshop/docs/board_preview.png create mode 100644 studies/202607_CX_Discovery_Workshop/docs/cx_discovery_survey.md create mode 100644 studies/202607_CX_Discovery_Workshop/exports/.gitkeep create mode 100644 studies/202607_CX_Discovery_Workshop/notebooks/cx_discovery.ipynb create mode 100644 studies/202607_CX_Discovery_Workshop/pyproject.toml create mode 100644 studies/202607_CX_Discovery_Workshop/scripts/build_notebook.py create mode 100644 studies/202607_CX_Discovery_Workshop/scripts/export_report.py create mode 100644 studies/202607_CX_Discovery_Workshop/tests/conftest.py create mode 100644 studies/202607_CX_Discovery_Workshop/tests/test_session.py create mode 100644 studies/202607_CX_Discovery_Workshop/tests/test_staging.py create mode 100644 studies/202607_CX_Discovery_Workshop/tests/test_topics.py diff --git a/cxxm.md b/cxxm.md new file mode 100644 index 0000000..0c15e2c --- /dev/null +++ b/cxxm.md @@ -0,0 +1,453 @@ +Contact Center Exploration & Discovery Workshops +The Contact Center Discovery and Exploration workshops allow us to gain a clear perspective of your contact center operations. The discovery workshop is focused on developing an understanding of the current state architecture and IT support. + +I’ve attached a contact center survey to collect information and context in advance of the workshop and is also useful to develop business cases. + +# CX Exploration + +## Background +How many distinct lines of business are supported in the contact centre? + (eg, commercial, residential, retail, wholesale, etc) +Are you using contact center for internal Uses such as help desk, finance, HR, etc.? + +What channels do you support? + Apps + Voice + Video + Chat + SMS + Email + Social Media + Digital Assistants + +Payment card/PCI? + +What are the availability SLAs or targets for your technology platform? + +Mini org chart + +Reporting structure + - Executive leader + +What is the structure of decision making in their organization? Centralized or decentralized? + - Who are the key decision makers for implementing a plan for changes to the contact centre? + +How important is CX & EX to your organization's strategy? + - Is there an executive that is accountable for CX? CXO, CDO? + +Of your leading offers, what is the customer's top priority? + +Competitive pressures? + +Are their pending or recent acquisitions or spinoffs that require changes to their IT infrastructure and services? + +What do they view as the problems in their contact centre today and what are the primary causes? + +CX / Customer Success Leadership: +Are your contact centers managed by the same person? + - Managers: + - Team Leads: + - Agents: + +Who carries the cost of contact centre agents and supervisors? + +What revenue is generated by the contact center? + +Do you have KPI targets for CX?: + CSAT: + NPS: + CES: + How are you doing? + +Is there a VOC program in place? + • ROI/business value known? + • How do customers rate the experience they receive from your organization? 0-5 + + +What are the key features of their corporate culture? + +Is their a Voice of the Agent, or Employee satisfaction survey in place? + - How are they doing? + + +Automation strategy? + +Any inflight projects? + - Any CX or EX improvement initiatives? + +Decision + +Channel management strategy? + +Are your customer experiences personalized? + +Do you have a clear set of design guidelines for CX? + Personas + Journey Mapping + Tools: + +How are processes managed? + +## CX Strategy +How is the value of Customer Experience defined within your organization? + - CX is a key BPI, recognized & measured as a financial value + + + +Strategic Value +What revenue is generated by the contact center? + +What are the key capabilities / services that are delivered by the contact centre? + + + +Proposition +How are you using CX innovation to create market disruption? + +How are competitors using CX to create competitive differentiation? + + +Organization Structure & Operating Model +Is there an executive that is accountable for CX? CXO, CDO? + +Is there a CX team? + Do the CX insights team regularly educate the business + +How are decisions made in the organization, is it centralized or decentralized? + - Who are the key decision makers for investment and changes to the contact centre'? + - Channel management strategy? + + +Who carries the cost of contact centre agents and supervisors? + +Are they managed by the same person? + + +What are the teams? + +How are processes managed? + +Describe your automation strategy. Are there any desires or goals related to the contact centre? + - Who is your leader for Data & AI? + + + +Are there any inflight projects that would impact the contact centre? + +Are there recent or pending acquisitions or spinoffs? + +Insight +How do you use analytics & data to generate a consolidated view of your customer experience? + + +Is there a VOC program in place? + • ROI/business value known? + • How do customers rate the experience they receive from your organization? 0-5 + + +Approach +Continuous Improvement +How is customer insight used to drive CX improvement, loyalty and profitability? +How do you anticipate needs? + +Do you have a clear set of CX design guidelines for CX? + Personas + Journey Mapping + Tools: + +Do you have KPI targets for CX?: + CSAT: + NPS: + CES: + How are you doing? + + +Employee Engagement +Please describe you about your employee / Agent engagement strategy + +How engaged are your people in delivering the customer experience? + +Do you have a VoA/VoE program in place? How are you doing? + +## Channels + +May 6, 2025 +2:52 PM + +Inbound + +Hours of operation + +Who contacts the contact center? (Demographics, their situation) + +Are certain callers or groups prioritized? + +Languages? + English + Canadian French + Spanish + + Video + Average number of active agents: + Voice + Average number of active agents: + Toll Free numbers & DIDs: + Approximate quantities or a list + Hours of operation? Any 24x7? + Average Wait Time: + Average Abandon rate: + Average Handle Time: + Average Call Hold Time: + Average After work call time: + Time to authenticate a caller: + % of calls transferred? + Internally? + Externally? + 3rd parties handling certain types of calls, or being conferenced in? + Courtesy Callback/Virtual Hold + Post Call Survey + First Call Resolution Rate? + Average revenue per call (sales)? + Email, range of logged in users: + ○ Response time: + ○ Email server + Chat, range of logged in users: + Web Chat Internal + Web Chat External + App Integration / embedded + SMS + Facebook Messenger + WhatsApp + Telegram + iMessage + Web Site Forms + Mobile Apps + +Top 3-5 Inbound contact reasons and approximate % of calls: + 1. + +Cost Per call? +Average Handle Time? + +Busiest days: + +Least busy days: + +Seasonal variances? + +What are your most difficult, commonly occurring calls? + +What is the easiest commonly occurring call? + + +Outbound + +Hours of operation + + Voice, range of logged in users: + Preview, volume + Predictive dialer + Email, range of logged in users: + SMS, range of logged in users: + Recorded announcement, ports: + Self service applications + Transfer to agent + Live agent connect + Campaign management + DNC management + +Top 3-5 outbound contact reasons and approximate % of calls: + 1. + + +After call work? + + +## Agent & Supervisor Environment +Location types: + - WFH: + - Offices: + + Hard phone + Soft phone + CODEC? + Headset, wireless?: + Agent greeting or pre-recorded messages + Whisper announcement +PC + Desktop + Laptop + VDI +Agent & Supervisor desktop (omnichannel?): + Custom gadgets + Screen pops + Workflows +Standard browser: +SSO: +Applications used to handle calls: +Knowledge Management: + +## Routing & Automation + Self Service + IVR Persona? + Branding? + Style guides? + Voice actors? + DTMF + Speech + Speech recognition + Text To Speech + Natural Language Understanding + Voice Biometrics + Self service applications: + ID & Validate + Deflection + Situational Offer (Outage/ Time of Day / Scheduled) + API integration: + CRM + Intent Capture + Intent prediction + Offer push based on prediction/account attribute + Virtual Agents + Processes + Agent Assist + RPA + Current challenges or desired capabilities + Process management + Desire to automate + DevOps team? + +Digital Assistant Apps + Alexa + Google Assistant + Siri + + +## Routing & Automation + Self Service + IVR Persona? + Branding? + Style guides? + Voice actors? + DTMF + Speech + Speech recognition + Text To Speech + Natural Language Understanding + Voice Biometrics + Self service applications: + ID & Validate + Deflection + Situational Offer (Outage/ Time of Day / Scheduled) + API integration: + CRM + Intent Capture + Intent prediction + Offer push based on prediction/account attribute + Agent Assist + RPA + Current challenges or desired capabilities + Process management + Desire to automate + DevOps team? + +Digital Assistant Apps + Alexa + Google Assistant + Siri + + +Workforce Engagement + +May 6, 2025 +2:50 PM + +Call Recording/QM + • How is call recording used? + Compliance + Screen capture + Voice transcription + Real time + Desktop analytics + Retention period + Quality Management + Do you have a quality team? + Who do they report to? + How many people work for the team? + Scorecards + Score method and metrics? + How many assessments are conducted? + Coaching + Live Monitor + • Locations with CR + • Number of Named Agents: + + +Workforce Engagement + • What is your recruitment process? + • What qualifications are required for the call center? + • What is the average staff tenure? + • What is the attrition rate? + • What proportion of the staff leave for other positions in the company per annum? + ○ Are staff hired for the CC from other parts of the organization? + • Do you measure agent & supervisor experience? + ○ How are they doing? + ○ What type of recognition program do you have in place? + • Agent adherence measure? + ○ KPIs + ○ Gamification + ○ How long is a shift? + ○ What breaks are allocated + ○ What annualized utilization % do you calculate? + • Forecasting & Scheduling + ○ Peak call volume days, time of month, year? + ○ Validate historical data + ○ How are calculations performed (algorithms used) + ○ WFM Interval (15/30 minutes) + • Intraday/ Realtime adherence + ○ What happens when you are out of compliance, surprises happen? + • Payroll Integration + ○ Payroll platform + • Satisfaction with current tool(s)? + ○ Multiskilled agents + ○ FTE Calculations + • Agent self-service? + ○ How are absences reported? + ○ Shift bids / swaps + ○ Performance metrics + • Number of Named Agents: + • Integration to 3rd party + ○ outsourcer / overflow: + ○ Payroll: ADP / Workday + + +Training + • Onboarding process + ○ How long is it? + ○ Training format? + ○ Assessment? + eLearning + QM Integration + +## Reporting & Insights +Reporting + • Real time + • Historical + • What are the key metrics that you report on? + Data source integration + Dashboards + Wallboards + Agent & Supervisor status + +Analytics & Insights + Do you have an integrated view of customer details and contact history? + CRM: + Does your contact centre collect and use customer insight? + Predictive engagement: + What sort of data analysis do you perform? + Do you have an analytics or business insights team? + How many people? + BI Platform: + What executive level reporting do you perform? + Marketing Team interlock + diff --git a/studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_no_current_state.ipynb b/studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_no_current_state.ipynb index 86721c9..292c7f9 100644 --- a/studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_no_current_state.ipynb +++ b/studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_no_current_state.ipynb @@ -36,7 +36,14 @@ "cell_type": "code", "execution_count": 1, "id": "26632e8d", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:09.753197Z", + "iopub.status.busy": "2026-07-13T22:00:09.752920Z", + "iopub.status.idle": "2026-07-13T22:00:10.296464Z", + "shell.execute_reply": "2026-07-13T22:00:10.295587Z" + } + }, "outputs": [ { "name": "stdout", @@ -157,17 +164,24 @@ "cell_type": "code", "execution_count": 2, "id": "7b33a037", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.299016Z", + "iopub.status.busy": "2026-07-13T22:00:10.298717Z", + "iopub.status.idle": "2026-07-13T22:00:10.315415Z", + "shell.execute_reply": "2026-07-13T22:00:10.314637Z" + } + }, "outputs": [ { "data": { "application/mercury+json": { - "model_id": "8927a9e1a74b44ca98a8429274fcca31", + "model_id": "fbc4f6246d0d4b36852ad6ad5f252d84", "position": "sidebar", "widget": "MarkdownWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "8927a9e1a74b44ca98a8429274fcca31", + "model_id": "fbc4f6246d0d4b36852ad6ad5f252d84", "version_major": 2, "version_minor": 0 }, @@ -247,22 +261,29 @@ "cell_type": "code", "execution_count": 3, "id": "7e4e12ce", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.317817Z", + "iopub.status.busy": "2026-07-13T22:00:10.317550Z", + "iopub.status.idle": "2026-07-13T22:00:10.360840Z", + "shell.execute_reply": "2026-07-13T22:00:10.359993Z" + } + }, "outputs": [ { "data": { "application/mercury+json": { - "model_id": "dbc3ef2687aa4a6d988f7d5e88431c5e", + "model_id": "4f18a5dd5d4245a9b7558564825d4a09", "position": "inline", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "dbc3ef2687aa4a6d988f7d5e88431c5e", + "model_id": "4f18a5dd5d4245a9b7558564825d4a09", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -271,17 +292,17 @@ { "data": { "application/mercury+json": { - "model_id": "78509e85c62c4dae93d36794f5549dac", + "model_id": "4f1b8f8777ef43deb835fe53c4dd2994", "position": "inline", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "78509e85c62c4dae93d36794f5549dac", + "model_id": "4f1b8f8777ef43deb835fe53c4dd2994", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -290,17 +311,17 @@ { "data": { "application/mercury+json": { - "model_id": "ed62020b820644b18b7a0f984f34fee2", + "model_id": "27e26a695a9d48c9bae29e3402ae1132", "position": "inline", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "ed62020b820644b18b7a0f984f34fee2", + "model_id": "27e26a695a9d48c9bae29e3402ae1132", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -309,17 +330,17 @@ { "data": { "application/mercury+json": { - "model_id": "b1fb0830beea4568812c65a865f1992a", + "model_id": "6ada443fa3844d198bc69221d8867bbc", "position": "inline", "widget": "DateInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "b1fb0830beea4568812c65a865f1992a", + "model_id": "6ada443fa3844d198bc69221d8867bbc", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -328,17 +349,17 @@ { "data": { "application/mercury+json": { - "model_id": "b83e27df803a478bac5dd66a21ed9e59", + "model_id": "bb1cf20444e2490597fd26df35490de9", "position": "inline", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "b83e27df803a478bac5dd66a21ed9e59", + "model_id": "bb1cf20444e2490597fd26df35490de9", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -347,17 +368,17 @@ { "data": { "application/mercury+json": { - "model_id": "ff3bc880230a4a4a9073c4bda91e77fe", + "model_id": "7971c319317c4e90bdfe69607c9e0de7", "position": "inline", "widget": "DateInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "ff3bc880230a4a4a9073c4bda91e77fe", + "model_id": "7971c319317c4e90bdfe69607c9e0de7", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -366,17 +387,17 @@ { "data": { "application/mercury+json": { - "model_id": "4ba0efa7dcef40a1ac07e393d07de624", + "model_id": "7013bd8d97d040cbb8172345f8a2829b", "position": "inline", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "4ba0efa7dcef40a1ac07e393d07de624", + "model_id": "7013bd8d97d040cbb8172345f8a2829b", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -385,17 +406,17 @@ { "data": { "application/mercury+json": { - "model_id": "9e9fdf5751d544bd98d46d3528f2e4e8", + "model_id": "fd23a1e2c3f84fd4ba4803b26fdec9ff", "position": "inline", "widget": "DateInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "9e9fdf5751d544bd98d46d3528f2e4e8", + "model_id": "fd23a1e2c3f84fd4ba4803b26fdec9ff", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -404,17 +425,17 @@ { "data": { "application/mercury+json": { - "model_id": "a41c8514526e4130b3ce57f8494b85d8", + "model_id": "1ebe071b962145cdbed25a1ae3dc8ccb", "position": "inline", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "a41c8514526e4130b3ce57f8494b85d8", + "model_id": "1ebe071b962145cdbed25a1ae3dc8ccb", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -423,17 +444,17 @@ { "data": { "application/mercury+json": { - "model_id": "78e58d47e33b413ca597ff326a9cb27b", + "model_id": "336a0118e33249788ad6521ecbba63d9", "position": "inline", "widget": "DateInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "78e58d47e33b413ca597ff326a9cb27b", + "model_id": "336a0118e33249788ad6521ecbba63d9", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -482,7 +503,14 @@ "cell_type": "code", "execution_count": 4, "id": "52d1e89f", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.363655Z", + "iopub.status.busy": "2026-07-13T22:00:10.363368Z", + "iopub.status.idle": "2026-07-13T22:00:10.385562Z", + "shell.execute_reply": "2026-07-13T22:00:10.384873Z" + } + }, "outputs": [ { "name": "stdout", @@ -491,7 +519,7 @@ "current-state total $7.3M/yr (seed: $7.3M; deck 3-yr $22.0M — deck rounding)\n", "deck CCaaS 3-yr (no ramp) = $15.5M (deck: $15.4M)\n", "licence run-rate: contracted $3.2M/yr (deck pitched $4.3M/yr — as-pitched stack keeps it)\n", - "ramp-adjusted licences by year: {2026: '$1.6M', 2027: '$3.2M', 2028: '$3.2M'}\n" + "ramp-adjusted licences by year: {2026: '$3.2M', 2027: '$3.2M', 2028: '$3.2M'}\n" ] }, { @@ -707,7 +735,10 @@ "# The current-state table above is retained for reference only; it is\n", "# forced to $0 here so it carries NO weight downstream.\n", "current_by_year = {y: 0.0 for y in YEARS}\n", - "licence_by_year = licence_costs_by_year(RAMP_MONTHS, LICENCE_ANNUAL)\n", + "# Licences are INVOICED in full from year 1 ($3.2M), even though the\n", + "# order-form ramp gives free months operationally — CTM's invoice does\n", + "# not net the ramp down. Bill the full contracted annual every year.\n", + "licence_by_year = {y: LICENCE_ANNUAL for y in YEARS}\n", "\n", "backstage(f\"current-state total {money(current_state['annual_cost'].sum())}/yr \"\n", " f\"(seed: {money(TCO_VERBATIM['current_annual'])}; deck 3-yr \"\n", @@ -762,7 +793,14 @@ "cell_type": "code", "execution_count": 5, "id": "c7e86e80", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.387332Z", + "iopub.status.busy": "2026-07-13T22:00:10.387171Z", + "iopub.status.idle": "2026-07-13T22:00:10.435879Z", + "shell.execute_reply": "2026-07-13T22:00:10.435044Z" + } + }, "outputs": [ { "name": "stdout", @@ -911,22 +949,29 @@ "cell_type": "code", "execution_count": 6, "id": "5ace8c50", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.437620Z", + "iopub.status.busy": "2026-07-13T22:00:10.437432Z", + "iopub.status.idle": "2026-07-13T22:00:10.444270Z", + "shell.execute_reply": "2026-07-13T22:00:10.443168Z" + } + }, "outputs": [ { "data": { "application/mercury+json": { - "model_id": "17cb8e9cdcb1451e9ba532a01a3f9a2e", + "model_id": "4c89a258ad0048e6a2797233bd2c04d2", "position": "sidebar", "widget": "CheckboxWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "17cb8e9cdcb1451e9ba532a01a3f9a2e", + "model_id": "4c89a258ad0048e6a2797233bd2c04d2", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -944,7 +989,14 @@ "cell_type": "code", "execution_count": 7, "id": "fe3572d2", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.446194Z", + "iopub.status.busy": "2026-07-13T22:00:10.445998Z", + "iopub.status.idle": "2026-07-13T22:00:10.457166Z", + "shell.execute_reply": "2026-07-13T22:00:10.456462Z" + } + }, "outputs": [ { "name": "stdout", @@ -1103,7 +1155,14 @@ "cell_type": "code", "execution_count": 8, "id": "a06e90b9", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.459077Z", + "iopub.status.busy": "2026-07-13T22:00:10.458910Z", + "iopub.status.idle": "2026-07-13T22:00:10.542268Z", + "shell.execute_reply": "2026-07-13T22:00:10.541659Z" + } + }, "outputs": [ { "name": "stdout", @@ -1265,22 +1324,29 @@ "cell_type": "code", "execution_count": 9, "id": "977418e1", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.544997Z", + "iopub.status.busy": "2026-07-13T22:00:10.544753Z", + "iopub.status.idle": "2026-07-13T22:00:10.562447Z", + "shell.execute_reply": "2026-07-13T22:00:10.561099Z" + } + }, "outputs": [ { "data": { "application/mercury+json": { - "model_id": "6b80ee9107a6483c843063b90b59341e", + "model_id": "5985ba7b869548d4a55b0490fb0fa302", "position": "sidebar", "widget": "CheckboxWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "6b80ee9107a6483c843063b90b59341e", + "model_id": "5985ba7b869548d4a55b0490fb0fa302", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1289,17 +1355,17 @@ { "data": { "application/mercury+json": { - "model_id": "213fedc568424f12b2160bf25c4ba94e", + "model_id": "84926ebcbf1b4909870e0162052155da", "position": "sidebar", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "213fedc568424f12b2160bf25c4ba94e", + "model_id": "84926ebcbf1b4909870e0162052155da", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1308,17 +1374,17 @@ { "data": { "application/mercury+json": { - "model_id": "01f8dbc02c7742108ef578d56d29197c", + "model_id": "26ad610c103f4511853bbdcfd637a108", "position": "sidebar", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "01f8dbc02c7742108ef578d56d29197c", + "model_id": "26ad610c103f4511853bbdcfd637a108", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1327,17 +1393,17 @@ { "data": { "application/mercury+json": { - "model_id": "1e617074f6f74576b7639ac100ccf60a", + "model_id": "3946415fb4ac441fb7912a77a2f143d4", "position": "sidebar", "widget": "SliderWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "1e617074f6f74576b7639ac100ccf60a", + "model_id": "3946415fb4ac441fb7912a77a2f143d4", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1346,17 +1412,17 @@ { "data": { "application/mercury+json": { - "model_id": "52b0cc956e1e44dbb9df55d00d4395f8", + "model_id": "6190da45d1d444118fbd3272d96d09c4", "position": "sidebar", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "52b0cc956e1e44dbb9df55d00d4395f8", + "model_id": "6190da45d1d444118fbd3272d96d09c4", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1392,7 +1458,14 @@ "cell_type": "code", "execution_count": 10, "id": "9767177f", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.564909Z", + "iopub.status.busy": "2026-07-13T22:00:10.564722Z", + "iopub.status.idle": "2026-07-13T22:00:10.575688Z", + "shell.execute_reply": "2026-07-13T22:00:10.574705Z" + } + }, "outputs": [ { "data": { @@ -1538,7 +1611,14 @@ "cell_type": "code", "execution_count": 11, "id": "3f3102f4", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.578640Z", + "iopub.status.busy": "2026-07-13T22:00:10.578465Z", + "iopub.status.idle": "2026-07-13T22:00:10.628687Z", + "shell.execute_reply": "2026-07-13T22:00:10.627130Z" + } + }, "outputs": [ { "name": "stdout", @@ -1706,7 +1786,14 @@ "cell_type": "code", "execution_count": 12, "id": "e62ecfa7", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:10.636419Z", + "iopub.status.busy": "2026-07-13T22:00:10.636215Z", + "iopub.status.idle": "2026-07-13T22:00:12.215681Z", + "shell.execute_reply": "2026-07-13T22:00:12.213933Z" + } + }, "outputs": [ { "data": { @@ -1732,9 +1819,9 @@ "2028" ], "y": [ - 114000, - 662400, - 715200 + 114000.0, + 662400.0, + 715200.0 ] }, { @@ -1754,9 +1841,9 @@ "2028" ], "y": [ - 85500, - 550620, - 751680 + 85500.0, + 550620.0, + 751680.0 ] }, { @@ -1776,9 +1863,9 @@ "2028" ], "y": [ - 214299, - 1362323, - 1851816 + 214299.0, + 1362323.0, + 1851816.0 ] }, { @@ -1798,9 +1885,9 @@ "2028" ], "y": [ - 10551, - 67080, - 91500 + 10551.0, + 67080.0, + 91500.0 ] }, { @@ -1820,9 +1907,9 @@ "2028" ], "y": [ - 0, - 34185, - 69540 + 0.0, + 34185.0, + 69540.0 ] } ], @@ -1836,7 +1923,7 @@ "showarrow": false, "text": "$424K", "x": 0, - "y": 424350, + "y": 424350.0, "yshift": 12 }, { @@ -1847,7 +1934,7 @@ "showarrow": false, "text": "$2.7M", "x": 1, - "y": 2676608, + "y": 2676608.0, "yshift": 12 }, { @@ -1858,7 +1945,7 @@ "showarrow": false, "text": "$3.5M", "x": 2, - "y": 3479736, + "y": 3479736.0, "yshift": 12 } ], @@ -1965,7 +2052,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2001,7 +2088,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2025,7 +2112,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2061,7 +2148,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2088,7 +2175,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2124,7 +2211,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2139,7 +2226,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2175,7 +2262,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2331,7 +2418,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2367,7 +2454,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2458,7 +2545,7 @@ ], "sequential": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2494,13 +2581,13 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], "sequentialminus": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2536,7 +2623,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ] @@ -2692,8 +2779,7 @@ "zerolinewidth": 1.5 } } - }, - "image/png": "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7zxISp0FAABAbAg2sPx4pNWseZ1rSEaKDCxXrlxu277/zv28a9dOa9vuZte7Kr5GyrYfvre1a8/toal/BCscnTBhrFtWqlRZ9w9o73NbvvnaZs+eYfnzn5lzTw4f/s1u73Kna1TpH8rqmfP9d1tty5av3T/U1XDLnDmz620g+gd8lSrVXaMxfHs8CQWW27adadRVqlTVKlxTMRQ++O27GsoD3u1rDz78hFsuXjByRZYr7J3+b1nxsCD410MHrU3bDpYzV67QsunTJlvGDBnO68UVXqaiobp79ux2PQwTCi4i93falElWslQpK39VhXNeC1//xE/HWYYMGa1KteqhuQ4jv18PU2jVqp0r5/j2S/MI5smbN9QzKb45LCMbqGqIqwegwiQ1nhS4KXRNqC5EBhXqfRTfdv3626/nNf7DRe6r6oPq6oFffrHTroG21R557M++jdGE6p5fuYZ7f0A/a9T4BitTplxomezbu8e++GKJazRXrFjZHbtwiQWW77+nXpMRgWWlyq5H0fp1a61tWGDZr+8brlGueq4GrnopVql65rhENly3bNls69eusXbqGXeW1n311RVc76K3+7xuWbNlt1at2rhQRT6bO8v1MNNyUQ+qvHnyuvoeWQ8UJuTIkTMU/nviDSybt3K9bUU9pxTAqNxUZpE9v/wCS32v3zGKrFvhVCcGf/Ceq58KPjzaT/VKrXzt/+baU50c8F6/c8LjL1ettJ9//tEFupH1zjvH1GPKb7sSOu/D13XmHOpr9953/nU4ssy1P+PHj7G77r7Hd7+99WbLmu2C98Xjd231CyzjO/8iQzXx22a/sgvndy3XfSyyvodLqB7rXqS5NFXuuubpATEaQq0wtHXbm86bhiD8Oqw/vGnkgM7BcJH7mtD1bfXqlW67qp8N4eILLLUP2XPkdFNFePQHLm9kQfj3KZRST3lNHxEusbINrwdJ+beAeukmVCfDA8uErrVJrf9JXYeE7nlZsiS5jvrdI8L3T3WiRas2od6JP/643z3QRtfyyHKI73qY1HK90O/yOw+SUmcBAAAQGwINLPUPVQ290jCnSOENn6+/3mibNm5wTzfV+zUcu0rV6la0aLF4GymRjS79I1k95aqGNZg83ue++eZrF4q0j+epph8Oft8633qHG1qo3h9qNKkxoX+Ya/hppPDt8SjcGDzovVADRI0PL7D0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Xn179NFHrEiRom5Zhw43Wf78+a1379728suvWNGiRW3NmtWWNm1a93r37j1s7Nix1qZNGxs+fJhbBuDSIbAEAAAAAAApwuLFS6xly5b22muvWc+ePdw2HzhwwHLkyOF+VqD5888/29Chw+yFF16wGTNmWO3atc7Zt88//9zatWtvq1attFKlSoWWy6OPPmrDhg23EydO2JAhH1r79u1t586dVrFiJddTs3r1am6dAC4tAksAAAAAAJAibNy40WrXvs6qVLnWXn31NatZs8Y52z1y5Ejr1es+9/Ptt99u77zT/+wr/6OekuoxqdevueYa+9OfuoUCz65du9mGDRssX768ljZtOps8eZLrdTl48IdWuXJlN5x85coVZ9cE4FIhsAQAAAAAAClGnz597dlnn7Xjx49b48aNrX//flaoUCG3/Zrf8osvvrDRo8fYhAkT7P33B9gtt9xyzr4tWLDQRowYYd9+u8WWLFlqhQsXtgUL5lvu3Lmtdes2dvjw79arVy+7995etnDhAvdwn27dutq2bdtt2rRp7kE/AC4tAksAAAAAAJCiaA7Lt99+2/r3f8dKly5tixcvCs03KadOnbLSpctYw4YNbfDgD0LLI02cONH1qnz99detR4/uVrduPcubN6+NGTPaKlS4xvLkyWObNm2ydevW2ptvvmnvvz/Qfv75p9DnAVwaBJYAAAAAACBF+vvf/259+77tAsVixYqF9kFzWZYocaV7gviHHw62n376yQWa3tBvzzfffGPVq9dw6/nLX/7s5qqsVKmSffTRCPeE8TfeeNOtY/ToUa5X5+uv/9d27NhuWbNmDa0DwMVHYAkAAAAAAFKENWvWWO/eL7ong+fIkd2FleptuXXrt/a3v/3NDh8+4oZ4z5kz2774YpkNGPCeGxJerlx5y5Qpk61du8aefPJJy5Ili2XOnNkmTJjo5sWcM2eOVatW1YWcTZs2tUGDBrr5KtX78oUXnndDz1955VX3IJ9NmzZawYIFU0R5ASkVgSUAAAAAAEgRFi1abE899ZQLGU+ePOmGg7/yyssuZHz66adt1KjRtn//fhda9uzZ0x599BG3X02aNLHMmbO4h+j06NHT5s6dawcPHnSff+qpJ0PzXObJk9c6d+7s5sWMpHBUPTFXrFhuZcqUCS0HcPERWAIAAAAAgBRl1qxZ7mE4egBOzpw5U9S2A0hc1AaWY0aNsHbtb7aMmTKFNhYAAAAAAGDLli02evRoe/zxx91QbwCpS4oKLGdMn2q//PyTHTly2PLkzWctWra2dOnSnXdEPpsz03bs2GYZMpy5aNWt38h1B//110M2cEB/697jPsuWPfvZd58xfdpkN2lu3XoNQ8sAAAAAAAAABCvqAkuFigvmf257du+ybNlzWLFixa1mretcqRw7etQyZMzofv70k7Fu0tyrK1Q8r8SmT51sVatVt/wFzp0EVxPxjh87ykqWKm2tbmwbWr5v314bO+YjK1myjLVo1Tq0HAAAAAAAAECwoi6wnDplohUtWswqVa7iSuLEiRPn9aI8fvy4TfhkrF1Xp54VKVI0tNwzftwYu6FZS8uWLVtomWzZstm+27rFdu/eZS1btXWT6con48ZY6TJlbfPmr+3mjp3PvhsAAAAAAABA0KIusJw9a7qlTZPGGjRqamnSpDmvPBbM/8xWf7nSKlSoaI2bNg8tD6fel8eOHXVPALu2SjXXS1PWrV1thw4dtPz5C9jGjRusdZv2rifn4kULrGmzFjbx07HWpevd7r0//rjH/RcAAAAAAACIRXnyFLgsux11geWpU6ds1crltuWbry1fvvxWs3YdN7dkOPW6nDNrhuXImdNqX1cntDzSjz/ut6mTJ7hgUz0xly9banFxcVa9Ri0bPnSQtW7TwebNm2u1al1vufPksaFDBlqPnve7zx45/NvZtQAAAAAAAACxJ1PmKy7LTkddYBnu+++32swZU+3u7r0sbdq0oeWyf99e1xvz1tu7hZb5UW9M9aqsV7+RLVo4zz1sp1KlKrZp41e2bt0a956OnW5z/+3X9w174KHH3M8AAAAAAAAAghd1gWX4nJUnT560gQP62Z133eMetqPfvdc0jFtBZPMWN9rRI0fslwO/WIECBd17vHDz9OnTNmnCeLuyZCk3J+bcOTOtcOEiVv6qCu61USOHWp26Dax48Svd+/v2ed0eevgJ9zMAAAAAAACA4EVdYDl71jTbv3+/m7/y1MmTLlysUrW6Cyc1x6RZnMXFmeXImduaNm1uGTNlcr0lV65cZrd3udO2b9tm8z6fbXFp4uz0qdNWrHgJ17tSQ8GnT5tsZcqWs9Kly/qW9Dv93rKe9z5w3kN+AAAAAAAIt6tt29DPAIJRaOLEYL4Il13UBZaeMaNGWLv2N7tAEgAAAACAaEJgCQSPwDJ2RG1guX79GitfvgK9HQEAAAAAUYfAEggegWXsiNrAEgAAAAAAAEDsIbAEAAAAAAAAEDUILAEAAAAASKYDw9OHfgYQjBx3HA/mi3DZEVgCAAAAAJBMBJZA8AgsYweBJQAAAAAAyURgCQSPwDJ2EFgCAAAAAJBMBJZA8AgsYweBJQAAAAAAyURgCQSPwDJ2EFgCAAAAAJBMBJZA8AgsYweBJQAAAAAAAICoQWAJAAAAAAAAIGoQWAIAAAAAkEztGnwc+hlAMCbM6xTMF+GyI7AEAAAAACCZCCyB4BFYxg4CSwAAAAAAkonAEggegWXsILAEAAAAACCZCCyB4BFYxg4CSwAAAAAAkonAEggegWXsILAEAAAAACCZCCyB4BFYxg4CSwAAAAAAkonAEggegWXsILAEAAAAACCZCCyB4BFYxg4CSwAAAAAAkonAEggegWXsILAEAAAAACCZCCyB4BFYxg4CSwAAAAAAkonAEggegWXsILAEAAAAACCZCCyB4BFYxg4CSwAAAAAAkonAEggegWXsILAEAAAAACCZCCyB4BFYxg4CSwAAAAAAkonAEggegWXsILAEAAAAACCZCCyB4BFYxg4CSwAAAAAAkonAEggegWXsILAEAAAAACCZCCyB4BFYxg4CSwAAAAAAkonAEggegWXsILAEAAAAACCZCCyB4BFYxo4UH1gOGzrIunbrHjtHDAAAAABw2RFYAsEjsIwdqS6w/O2332zG9Cl27NgRO3L4iF119TVW+7o67oj++ushGzigv3XvcZ9ly579nKM8fdpky5o1q9Wt1zC0DAAAAAAAPwSWQPAILGNHig0sd+7cYcuWLraff/nZcmTPYVWr1bArS5ZyR+7YsWOWIUMGO378uA16/x3r0vUuy5Ytm+3atcvGjx1lJUuVtlY3tg0d5X379trYMR9ZyZJlrEWr1qHlAAAAAAD4IbAEgkdgGTtSbGA54N23rVPn2y1XrtzuaJ08edLSpk17zpE7dPCgjRs7ym6/404XYG7Zstm+27rFdu/eZS1btbU8efK6930yboyVLlPWNm/+2m7u2PnspwEAAAAA8EdgCQSPwDJ2pNjAcvAHA6xOnXpWrvzVvkfr49Ef2c6d261Fy9ZW/qoKbtm6tavt0KGDlj9/Adu4cYO1btPe9uzeZYsXLbCmzVrYxE/HWpeud7v3Hj16xP0XF9vp0E8ALrW40E8AAAC4ODJmzOT+S2AJBM8LLI8ePRz8lydb6miPede8oKXYwPLw4d9t6ZJFtmfPLjeUu3qNWuf3sDx00CZNGG8NGja1IkWL2vJlSy0uLs69d/jQQda6TQebN2+u1ap1veXOk8eGDhloPXre7z67b++Os2vBxZU6TlggJYjjdAMAALjo8uYr7P5LYAkEzwss9+3dGfyXJ1vq6LCVL3+R0B4FKcUGlp7Tp0+74HLvnt3W7qaOoeWeVSuXu3CzTt0GtmjhPPewnUqVqtimjV/ZunVr3Hs6drrNui4+vgAAIABJREFU/bdf3zfsgYcecz8DAAAAABAfAksgeAwJjx0pNrA8ceKEpUuXzh2p/fv22rRpk6xrt+7uQTvp06d3y0+dOmXjx422ChUq2tUVKtrcOTOtcOEiboi4gs5RI4e6ILN48Svd+/v2ed0eevgJ9zMAAAAAAPEhsASCR2AZO1JkYKmwcvzY0XbaTlucxdnp06esTt2GVrRYMfv2229s0YJ5ljZdWhdYlipVxq6vU98d0enTJluZsuWsdOmyvkf4nX5vWc97HwgFoQAAAAAA+CGwBIJHYBk7UmRgGW7Y0EGuZyUAAAAAAEEhsASCR2AZO1J8YLlm9UqrfG212DliAAAAAIDLjsASCB6BZexI8YElAAAAAABBI7AEgkdgGTsILAEAAAAASCYCSyB4BJaxg8ASAAAAAIBkIrAEgkdgGTsILAEAAAAASCYCSyB4BJaxg8ASAAAAl8ysWbOsY8dO9v3331nOnDlDywEgpSOwBIJHYBk7CCwBAABwSezZs8deeKG3DRkyxB544H5r0aKFNWrUyLZt22b//OfTNmfOHMuQIYN16HCT/fvf/7a0adOGPivFihW3gwcPhn6XJk2a2Pjx4+yDDz6wxx573F588UV78MEHQq+vXr3aGjRoaPfc09NeffXV0HIAuNgILIHgEVjGDgJLAAAAXHRHjx61WrVq265du6xChatt585dVr9+fRs48H17/vnnbcSIj6xTp462fv1XNnv2bOvfv5916dIl9Hl599333Hpk7dq1Nnr0aHvyySfs6aeftt69e9vLL79iRYsWtTVrVofCzu7de9jYsWOtTZs2Nnz4MLcMAC4FAksgeASWsYPAEgAAABfd4sVLrGXLlvbaa69Zz5493LIDBw5Yjhw57MiRI+7/GiK+b98+K1OmrD3yyMMuyIxP06ZNbd++/fbFF0stU6ZM9uijj9qwYcPtxIkTNmTIh9a+fXvbuXOnVaxYyeLi4qx69Wo2Y8aM0OcB4GIjsASCR2AZOwgsAQAAcNFt3LjRate+zqpUudZeffU1q1mzRui1cKNGjbJ77+1lgwd/YB06dAgtDzd37ly76aYO9t///te6d7/bLevatZtt2LDB8uXLa2nTprPJkye5XpeDB39olStXtq1bt9rKlSvOrgEALj4CSyB4BJaxg8ASAAAAl0SfPn3t2WeftePHj1vjxo3dsO9ChQqFXl+2bLnrGVm3bl0bM2Z0aHkkhZMLFy60jRs3WMaMGd2y1q3b2OHDv1uvXr1c4Llw4QL3cJ9u3bratm3bbdq0ae5BPwBwqRBYAsEjsIwdBJYAAAC4ZDSH5dtvv239+79jpUuXtsWLF7n5JjUnpULHsmXL2KeffmpZs2YNfSbcoUOHrHTpMta5c2fr27dPaHnduvUsb968LuisUOEay5Mnj23atMnWrVtrb775pr3//kD7+eefQu8HgIuNwBIIHoFl7CCwBAAAwCX397//3fr2fdsFirlz57Z69epb+vTpbfr0aZYrV67Q9//0008u0NRclzJz5kzr1OkWF0w2b9787LvMzVVZqVIl++ijEfbMM8/YG2+86Z5CPnr0KNer8/XX/2s7dmyPNwgFgD+KwBIIHoFl7CCwBAAAwEW3Zs0a6937Rfdk8Bw5sruwUr0tt2791oYMGWKPPfa4eyp4xYoV3fvz5Mltt956q5UrV949VGft2jVuufc08E2bNlrBggXdMilR4kr3IJ5Bgwa6+So1bPyFF553Q89feeVVe+GFF877DABcTASWQPAILGMHgSUAAAAuukWLFttTTz3lHr5z8uRJNxz8lVdediHj008/bW+++VbovXL11VfbkiWLrUmTJpY5cxb3EB3p3r2HTZ8+3fWWDJcnT143TFzzYkZSOKoenStWLLcyZcqElgPAxURgCQSPwDJ2EFgCAADgkpk1a5Z7GI4egJMzZ87QcgBI6QgsgeARWMYOAksAAABcMlu2bLHRo0fb448/7oZ6A0BqQWAJBI/AMnYQWAIAAAAAkEwElkDwCCxjB4ElAAAAAADJRGAJBI/AMnYQWAIAAAAAkEwElkDwCCxjB4ElAAAAAADJRGAJBI/AMnYQWAIAAAAAkEwElkDwCCxjB4ElAAAAAADJRGAJBI/AMnYQWAIAgFRtV9u2qXr/gGhUaOLEaNws4KIisASCR2AZOwgsAQAAAABIJgJLIHgElrGDwBIAAAAAgGQisASCR2AZOwgsAQBAqnZgePpUvX9ANMpxx/Fo3CzgoiKwBIJHYBk7CCwBAECqRmAJBI/AErGAwBIIHoFl7CCwBAAAqRqBJRA8AkvEAgJLIHgElrGDwBIAAAAAgGQisASCR2AZOwgsAQAAAABIJgJLIHgElrGDwBIAAKRqNCiB4NGgRCzg/gIEj/tL7IjawHLMqBHWrv3NljFTptg5GgAA4KKjQQkEjwYlYgH3FyB43F9iR4oJLE+cOGHzPp9je/bsslOnTlnOnLmtRcvWli5duvOO1mdzZtqOHdssQ4YzYWfd+o2scOHC9uuvh2zggP7Wvcd9li179rPvPmP6tMmWNWtWq1uvYWgZAABI+WhQAsGjQYlYwP0FCB73l9gRdYGlQsUF8z+3Pbt3WbbsOaxYseJWs9Z1dvr0adu+7QcrVryEOzrTpk6yQoUK27VVqp13tKZPnWxVq1W3/AUKhpbJrl27bPzYUVayVGlrdWPb0PJ9+/ba2DEfWcmSZaxFq9ah5QAAIOWjQQkEjwYlYgH3FyB43F9iR9QFllOnTLSiRYtZpcpV3FFQz0q/XpQLF3xu6dNnsFq1rw8t84wfN8ZuaNbSsmXLFlomW7Zstu+2brHdu3dZy1ZtLU+evG75J+PGWOkyZW3z5q/t5o6dz74bAACkBjQogeDRoEQs4P4CBI/7S+yIusBy9qzpljZNGmvQqKmlSZPG90gcOnTQxo8dbR1vuc2uuCJraLnn00/G2rFjRy1z5iyuB6Z6acq6tavdZ/PnL2AbN26w1m3au56cixctsKbNWtjET8dal653u/fu27fD/RcAAKRM+fIVcRtOgxIInteg5N/USI24vwCXD/eX4HnXvKBFXWCp+SlXrVxuW7752vLly281a9dxc0t6fvn5Z5s0abzdcEMrK1ioUGi5nx9/3G9TJ0+wxk2bW5EiRW35sqUWFxdn1WvUsuFDB1nrNh1s3ry5VqvW9ZY7Tx4bOmSg9eh5v/vssaNHz64FAACkRBkyZnSbTWAJBM9rUPJvaqRG3F+Ay4f7S/C8a17Qoi6wDPf991tt5oypdnf3XpY2bdozPSvHjbFWrdpYvvwFQu9LyOovV7rP1avfyBYtnOcetlOpUhXbtPErW7dujXtPx063uf/26/uGPfDQY+5nAACQOhBYAsFjyB5iAfcXIHjcX2JH1AWW4XNWnjx50gYO6Gd33nWPZcyUyUaPHG7XXV/Xipe48pwjdPTIEfvlwC9WoEBB9xmFm6IH9UyaMN6uLFnKzYk5d85MK1y4iJW/qoJ7bdTIoVanbgMrXvzM+vr2ed0eevgJ9zMAAEgdaFACwaNBiVjA/QUIHveX2BF1geXsWdNs//79bv7KUydPunCxStXqduzYMevz5quhcFFy5splzZq3cr0lV65cZrd3udO2b9tm8z6fbXFp4uz0qdPuqeLqXamh4NOnTbYyZctZ6dJlQ+sI906/t6znvQ/4PuQHAACkTDQogeDRoEQs4P4CBI/7S+yIusDSM2bUCGvX/mbXsxIAAOBC0aAEgkeDErGA+wsQPO4vsSNqA8v169dY+fIV6O0IAAD+EBqUQPBoUCIWcH8Bgsf9JXZEbWAJAABwMdCgBIJHgxKxgPsLEDzuL7GDwBIAAKRqNCiB4NGgRCzg/gIEj/tL7CCwBAAAqRoNSiB4NCgRC7i/AMHj/hI7CCwBAECqRoMSCB4NSsQC7i9A8Li/xA4CSwAAkKrRoASCR4MSsYD7CxA87i+xg8ASAACkajQogeDRoEQs4P4CBI/7S+wgsAQAAKkaDUogeDQoEQu4vwDB4/4SOwgsAQBAqkaDEggeDUrEAu4vQPC4v8QOAksAAJCq0aAEgkeDErGA+wsQPO4vsYPAEgAApGo0KIHg0aBELOD+AgSP+0vsILAEAACpGg1KIHg0KBELuL8AweP+EjsILAEAQKpGgxIIHg1KxALuL0DwuL/EDgJLAACQqtGgBIJHgxKxgPsLEDzuL7GDwBIAAKRqNCiB4NGgRCzg/gIEj/tL7CCwBAAAqRoNSiB4NCgRC7i/AMHj/hI7CCwBAECqRoMSCB4NSsQC7i9A8Li/xA4CSwAAkKrRoASCR4MSsYD7CxA87i+xg8ASAACkajQogeDRoEQs4P4CBI/7S+wgsAQAAKkaDUogeDQoEQu4vwDB4/4SOwgsAQBAqkaDEggeDUrEAu4vQPC4v8QOAksAAJCq0aAEgkeDErGA+wsQPO4vsYPAEgAApGo0KIHg0aBELOD+AgSP+0vsILAEAACpGg1KIHg0KBELuL8AweP+EjsILAEAQKpGgxIIHg1KxALuL0DwuL/EDgJLAACQqtGgBIJHgxKxgPsLEDzuL7GDwBIAAKRqNCiB4NGgRCzg/gIEj/tL7CCwBAAAqRoNSiB4NCgRC7i/AMHj/hI7CCwBAECqRoMSCB4NSsQC7i9A8Li/xA4CSwAAkKrRoASCR4MSsYD7CxA87i+xg8ASAACkajQogeDRoEQs4P4CBI/7S+xI8YHlsKGDrGu37rFzxAAAQLLQoASCR4MSsYD7CxA87i+xI9UFlgcPHLC5c2fZ4d9/s+PHj1u58ldb7evquCP666+HbOCA/ta9x32WLXv2c47y9GmTLWvWrFa3XsPQMgAAkPLRoASCR4MSsYD7CxA87i+xI8UGljt37rBlSxfbz7/8bDmy57Cq1WrYlSVLuVDyyJEjljdvPjt58qQNGfy+tbupo+XJk9d27dpl48eOspKlSlurG9uGjvK+fXtt7JiPrGTJMtaiVevQcgAAkPLRoASCR4MSsYD7CxA87i+xI8UGlgPefds6db7dcuXK7Y6Wwsm0adOed+RGfjTEGjS8wQoXLmxbtmy277Zusd27d1nLVm1diCmfjBtjpcuUtc2bv7abO3Y++0kAAJAa0KAEgkeDErGA+wsQPO4vsSPFBpaDPxhgderUc0O+4/Pd1m9t2RdL7JZbu7jf161dbYcOHbT8+QvYxo0brHWb9rZn9y5bvGiBNW3WwiZ+Ota6dL3bvffw77+6/wLR7nS0byAum7i4y/bVQFTInDmr2w4alEDwvAbl4cP8mxqpD/cX4PIJ3V/IbAKTOcuZf1MHLcUGlocP/25LlyyyPXt2uaHc1WvUOqeH5bfffmNLlyy0mzrcYpkzZ3HLli9banFxce69w4cOstZtOti8eXOtVq3rLXeePDZ0yEDr0fN+994ff9zj/gtEOzIpxI/agdiWO09+VwAElkDwvAblTz/uDf7LgUuM+wtw+Xj3FzKb4OTJUyC4LwuTYgNLz+nTp11wuXfPbjdXpahn5ZIlC6xDh86WMVOms+80W7RwnnvYTqVKVWzTxq9s3bo1bnnHTre5//br+4Y98NBj7mcAAJA6EFgCwWPIHmIB9xcgeNxfYkeKDSxPnDhh6dKlc0dq/769Nm3aJOvarbsdPXLEhg37wG7vcqdlyXKmZ6Vn7pyZVrhwESt/VQUXdI4aOdTq1G1gxYtf6V7v2+d1e+jhJ86+GwAApAY0KIHg0aBELOD+AgSP+0vsSJGBpcLK8WNH22k7bXEWZ6dPn7I6dRta0WLF7Nstm23qlImWP3/B0FEsW+4qq1K1mk2fNtnKlC1npUuXDb0W7p1+b1nPex8IBaEAACDlo0EJBI8GJWIB9xcgeNxfYkeKDCzDDRs6yPWsBAAA8EODEggeDUrEAu4vQPC4v8SOFB9Yrlm90ipfWy12jhjw/9u7D+goqjaM42+ooYQihCooTcSPDqJ0kRa6iA2VooJIlWpHkSpdadJRqoD0DiqKSu+KIEU6oSkgECCE5Dv3hh03SzYCJpfN3v/vHI+7k91kmZmdd99n750BANwRGkrAPBpK2ID6AphHfbFHog8sAQAA4kJDCZhHQwkbUF8A86gv9iCwBAAAfo2GEjCPhhI2oL4A5lFf7EFgCQAA/BoNJWAeDSVsQH0BzKO+2IPAEgAA+DUaSsA8GkrYgPoCmEd9sQeBJQAA8Gs0lIB5NJSwAfUFMI/6Yg8CSwAA4NdoKAHzaChhA+oLYB71xR4ElgAAwK/RUALm0VDCBtQXwDzqiz0ILAEAgF+joQTMo6GEDagvgHnUF3sQWAIAAL9GQwmYR0MJG1BfAPOoL/YgsAQAAH6NhhIwj4YSNqC+AOZRX+xBYAkAAPwaDSVgHg0lbEB9AcyjvtiDwBIAAPg1GkrAPBpK2ID6AphHfbEHgSUAAPBrNJSAeTSUsAH1BTCP+mIPAksAAODXaCgB82goYQPqC2Ae9cUeBJYAAMCv0VAC5tFQwgbUF8A86os9CCwBAIBfo6EEzKOhhA2oL4B51Bd7EFgCAAC/RkMJmEdDCRtQXwDzqC/2ILAEAAB+jYYSMI+GEjagvgDmUV/sQWAJAAD8Gg0lYB4NJWxAfQHMo77Yg8ASAAD4NRpKwDwaStiA+gKYR32xB4ElAADwazSUgHk0lLAB9QUwj/piDwJLAADg12goAfNoKGED6gtgHvXFHgSWAADAr9FQAubRUMIG1BfAPOqLPQgsAQCAX6OhBMyjoYQNqC+AedQXexBYAgAAv0ZDCZhHQwkbUF8A86gv9iCwBAAAfo2GEjCPhhI2oL4A5lFf7EFgCQAA/BoNJWAeDSVsQH0BzKO+2IPAEgAA+DUaSsA8GkrYgPoCmEd9sQeBJQAA8Gs0lIB5NJSwAfUFMI/6Yg8CSwAA4NdoKAHzaChhA+oLYB71xR4ElgAAwK/RUALm0VDCBtQXwDzqiz18NrCcPXO61G/wtKQMDLRnawAAgHhHQwmYR0MJG1BfAPOoL/ZIdIFlWFiYzJvzlTz2eHnJX6BgrFvq++9WyfHjRyVFiuiws3zFJyRHjhxy6dJFmTDuc3n1tTckKF26m4+OtmL5EkmbNq2Ur1DZWQYAABI/GkrAPBpK2ID6AphHfbGHzwWWKlT86ccf5NTJUAlKl15y5cotj5Z5XG+RX3Zul992/SJREiWlSz/mNbBcsWyJlChZSrJkzeYsU0JDQ2XenJmSJ28+qVW7nrP8zJnTMmf2DMmTJ7/UrFXHWQ4AABI/GkrAPBpK2ID6AphHfbGHzwWWy5YukvvvzyVFihbXWyEiIkKSJUumb1+4cF7SpUsv36xaLnny5PUaWM6bO1uqVQ+RoKAgZ5ly4MA+OXTwgJw8GSohtepJpkyZ9fL5c2dLvvwFZN++vfJ0o+duPhoAAPgDGkrAPBpK2ID6AphHfbGHzwWW336zQpImSSKVnqgqSZIkiXVLrFq5LM7AcsH8ORIefk1SpUotxYqX1KM0lV9/2SEXL/4tWbJklT17dkudug30SM51a3+SqtVryqIFc+TFl1/Rjz158oj+PwAASJyyZYuu/zSUgHmuhpLP1PBH1Bfg3qG+mOc65pnmc4FlZGSkbNu6WQ7s3yvBwVnk0cfK6XNLuvu3wNLlzz/PyrIlC6VK1RqSM+f9snnTBgkICJBSpcvItCkTpU7dhrJmzWopU6as3Jcpk0yZPEFea9FaP/dGxPWbvwUAACRGSZMl1y+bwBIwz9VQ8pka/oj6Atw71BfzXMc803wusHR3+PBBHU6+8morSZo0qbP8dgNLZcf2rXpUZYWKT8jan9foi+0UKVJcft/zm/z66079mEbPvKD/P2rEp9KmXUd9GwAA+AcCS8A8puwBAID/wucCS/dzVt64cUMmjBslzZq3lJSB0Vf8VjwDy2tXr8r5C+cla9Zs+jmucDMqKkoWL5wnD+bJq8+Jufq7VZIjR04p+PAj+mczv5oi5cpXkty5H9SPHzF8iLRr31nfBgAA/oHAEjCPwBIAAPwXPhdYfvvNcjl79qw+f2XkjRs6XCxeopTzghXPwFKNlty6dZM0frGZHDt6VNb88K0EJAmQqMgoyZX7AT26Uk0FX7F8ieQv8JDky1fg5m+KafSoYdLi9TZOYAoAABI/AkvAPAJL2CBZv3szTRKwWcS7nL7PFj4XWLrMnjld6jd4OsbISgAAgDtFYAmYR2AJGxBYAuYRWNrDZwPLXbt2SsGCjzDaEQAA/CcEloB5BJawAYElYB6BpT18NrAEAACIDwSWgHkElrABgSVgHoGlPQgsAQCAXyOwBMwjsIQNCCwB8wgs7UFgCQAA/BqBJWAegSVsQGAJmEdgaQ8CSwAA4NcILAHzCCxhAwJLwDwCS3sQWAIAAL9GYAmYR2AJGxBYAuYRWNqDwBIAAPg1AkvAPAJL2IDAEjCPwNIeBJYAAMCvEVgC5hFYwgYEloB5BJb2ILAEAAB+jcASMI/AEjYgsATMI7C0B4ElAADwawSWgHkElrABgSVgHoGlPQgsAQCAXyOwBMwjsIQNCCwB8wgs7UFgCQAA/BqBJWAegSVsQGAJmEdgaQ8CSwAA4NcILAHzCCxhAwJLwDwCS3sQWAIAAL9GYAmYR2AJGxBYAuYRWNqDwBIAAPg1AkvAPAJL2IDAEjCPwNIeBJYAAMCvEVgC5hFYwgYEloB5BJb2ILAEAAB+jcASMI/AEjYgsATMI7C0B4ElAAAAAAB3iMASMI/A0h4ElgAAAAAA3CECS8A8Akt7EFgCAAC/RkMJmEdDCRtQXwDzqC/2ILAEAAB+jYYSMI+GEjagvgDmUV/sQWAJAAD8Gg0lYB4NJWxAfQHMo77Yg8ASAAD4NRpKwDwaStiA+gKYR32xB4ElAADwazSUgHk0lLAB9QUwj/piDwJLAADg12goAfNoKGED6gtgHvXFHgSWAADAr9FQAubRUMIG1BfAPOqLPQgsAQCAX6OhBMyjoYQNqC+AedQXexBYAgAAv0ZDCZhHQwkbUF8A86gv9iCwBAAAfo2GEjCPhhI2oL4A5lFf7EFgCQAA/BoNJWAeDSVsQH0BzKO+2IPAEgAA+DUaSsA8GkrYgPoCmEd9sUeiDyynTpkoLzd51Z4tBgAA7ggNJWAeDSVsQH0BzKO+2MNvA8vQ0BMyb85Mea1Fa0kZGKi36KVLF2XCuM/l1dfekKB06WJs5RXLl0jatGmlfIXKzjIAAJD40VAC5tFQwgbUF8A86os9Em1geeLEcdm0YZ2cO39O0qdLLyVKlpYH8+TVW+7bb1bIpYsX5eTJUGn+SksnsAwNDdUhZp68+aRW7XrOVj5z5rTMmT1D8uTJLzVr1XGWAwCAxI+GEjCPhhI2oL4A5lFf7JFoA8txY0bKM881lowZ79Nb68aNG5I0aVJ9+/y5c5IhY0aZNGGMvPhSMyewPHBgnxw6eEAHmSG16kmmTJn18vlzZ0u+/AVk37698nSj5/QyAADgH2goAfNoKGED6gtgHvXFHok2sPxi0jgpV66CPFSwkNet5RlY/vrLDrl48W/JkiWr7NmzW+rUbSCnTobKurU/SdXqNWXRgjny4suv6MdeunRB/x/weVE+/wpxrwTcqz8M+Ia0adPrF0JDCZjnaij5TA1/RH0B7h3qi3muY55piTawvHIlTDasXyunToXqqdylSpdxRli6eAaWmzdtkICAAP3YaVMmSp26DWXNmtVSpkxZuS9TJpkyeYI+56Vy/txZ/X/A5xFKwQt2DdgufYbomRQEloB5robywnk+U8P/UF+Ae8dVX8hszMmQMfoztWmJNrB0iYqK0sHl6VMnpf5TjZzlimdgufbnNfpiO0WKFJff9/wmv/66Uy9v9MwL+v+jRnwqbdp11LcBAIB/ILAEzGPKHmxAfQHMo77YI9EGlhEREZIsWTK9pc6eOS3Lly+Wl5u8GmPLeQaWq79bJTly5JSCDz+ig86ZX02RcuUrSe7cD+qfjxg+RNq176xvAwAA/0BDCZhHQwkbUF8A86gv9kiUgaUKK+fNmSVREiUBEiBRUZFSrnxluT9XrhhbzjOwXLF8ieQv8JDky1fg5iNiGj1qmLR4vY0ThAIAgMSPhhIwj4YSNqC+AOZRX+yRKANLd1OnTLxlZCUAAIALDSVgHg0lbEB9Acyjvtgj0QeWO3dslaLFStqzxQAAwB2hoQTMo6GEDagvgHnUF3sk+sASAAAgLjSUgHk0lLAB9QUwj/piDwJLAADg12goAfNoKGED6gtgHvXFHgSWAADAr9FQAubRUMIG1BfAPOqLPQgsAQCAX6OhBMyjoYQNqC+AedQXexBYAgAAv0ZDCZhHQwkbUF8A86gv9iCwBAAAfo2GEjCPhhI2oL4A5lFf7EFgCQAA/BoNJWAeDSVsQH0BzKO+2IPAEgAA+DUaSsA8GkrYgPoCmEd9sQeBJQAA8Gs0lIB5NJSwAfUFMI/6Yg8CSwAA4NdoKAHzaChhA+oLYB71xR4ElgAAwK/RUALm0VDCBtQXwDzqiz0ILAEAgF+joQTMo6GEDagvgHnUF3sQWAIAAL9GQwmYR0MJG1BfAPOoL/YgsAQAAH6NhhIwj4YSNqC+AOZRX+xBYAkAAPwaDSVgHg0lbEB9AcyjvtiDwBIAAPg1GkrAPBpK2ID6AphHfbEHgSUAAPBrNJSAeTSUsAH1BTCP+mIPAksAAODXaCgB82goAQDAf0FgCQAA/BqBJWAegSUAAPgvCCwBAIBfI7AEzCOwhA2KfrDPhn8m4FN29i7gU68HCYfAEgAA+DUCS8A8AkvYgMASMI/A0h4ElgAAAAAA3CECS8A8Akt7EFgCAAAAAHCHCCwB8wgs7UFgCQAA/BoNJWAeDSVsQH0BzKO+2IPAEoD2zTffSKNGz8jhw4ckQ4YMrBUAfoOGEjCPhhI2oL4A5lFf7EFgCUBOnTolvXv3kcmTJ0ubNq19kVMzAAAgAElEQVSlZs2a8sQTT8RYM82bvyLz5s2T1atXS8mSJeTnn9dK7969ZNu27ZIlSxbp2rWLNG3a1Hm8smPHDqlWrbr+XbNnz5KIiAjJlCmzNG7cWEaP/lwiIyOlceMXZdWqVTJ//jypVKmS81wAiC80lIB5NJSwAfUFMI/6Yg8CS8By165dkzJlHpPQ0FB55JFCcuJEqFSsWFEmTBjvrJmJEydJp06d9G1XYKlCzfDwcHnyySdl0aLFsm/fPtm6dYvkyZNHP+7y5ctSvnwFOXjwoNSoUSPWwPK9996TkSNHydChQ+XVV1/RzwOA+EZDCZhHQwkbUF8A86gv9iCwBCy3bt16CQkJkcGDB0uLFq/ptXHhwgVJnz69vn38+HEdaBYq9LBs2rTZCSxPnz4twcHBEhAQoEdeqhGYs2bN1EGm8u6778qcOXMlRYoUUqhQoVsCy1KlSknXrl2lQ4f20qtXL/0cAEgINJSAeTSUsAH1BTCP+mIPAkvAcnv27JHHHntcihcvJoMGDZZHHy0dY400a9Zcj5Ls0qWzNG3azAks3bVv30FmzJghO3Zsl5w5c8quXbukQoWKMmXKZOnX7xPJkSNHjMBSjcI8dOiQPPvsszJ27BgdegJAQqGhBMyjoYQNqC+AedQXexBYApDhw0fIxx9/LNevX5cqVarI55+PkuzZs+sRldWqVZNly5bJX3/9KS+99PItgeXYseOkW7duepSkGi2pqIv3qN+1cOECPS3cM7B0GThwoLz+ekvnPgAkBBpKwDwaStiA+gKYR32xB4ElAE2dw3LkyJHy+eejJV++fLJu3VodUJ4+fUqPnlRXEW/Tpq3MnTtHX0QnadKkMn36dGnduo20bNlCBg0apH/Pzp07pWLFSvLFF5OkXLly0qDBU5I1a1aZPPlLSZMmjQ4s1Tktz549I1u3bpMxY0bLCy+8wFYAkGBoKAHzaChhA+oLYB71xR4+G1geO3ZU9u3dI1WerJ6gW2PmjCnyfOMmzn3Adu+//76MGDFSfv31Fz1VXF08x5O6uM6VK1ekSpUnpUGDBjJu3FhnWvewYcOle/fuNx/5j+eee06P3HSdw7Jfv75Sq1Zt2b9/vx7B6TkVHQDiCw0lYB4NJWxAfQHMo77YI9EFlt9/t0qOHz8qKVIE6q1UvuITerqp8tOP38uhQ39IVGSUlHq0jDzySBG9PPzaNVm2dJGEhV2SqCiRqtVDJGvWbPpnYz4fLq1aR09jBWykRkT26dNXXxk8ffp0OqxUoy0PHvxD1qxZIzdu3NCrZePGjdK//wDp37+/NG3aRJ+38uuvv9YBpxo5qRQtWkRy586trxju0qVLV8mU6T4ZNmyYPPzwwzGuEn7gwAGpXPkJyZQpk/z880+SNm1a53kAEF9oKAHzaChhA+oLYB71xR4+GVju+nWn/k+d7y5V6jRSrXpNCQpKp7fKimVLpETJUpLlZuDosmf3Ltm793ep3+BpCQ8Pl2lTJsmzz7+kA5BVK5dJpszBUrJkaTlz5rQsX7pImjSLvhoygSVst3btOn21bnXxHRVOqungAwcOkKpVq8ZYNYsXL45xDssnn3xStmzZ6vxccZ8a7hLbOSxdgaXyxRdfyJtvdpR27dpKnz59bj4LAOIPDSVgHg0lbEB9AcyjvtjD5wLL8+fPybw5s+Tlpq9K8uTJJTIyUk81dU03nTd3tlSrHiJBQUExttLCBXOlSJGikidvfn1/zQ/f6ZCzRMnSMmrEUGnZqp3+fcr0qZOkRs06kjk4ixNYhoVdlgXzv5aq1UIkS5as+nGATdQ5KtXFcg4fPiQZMmSw6Z8OwM/RUALm0VDCBtQXwDzqiz18LrC8ePFvmTHtS2n0zAt6VKSnBfPnSHj4NUmVKrUUK15ScuXKrZdPnTJRQkLq6hBS2b5ti/z99wV5vGwFGTdmpLRt30kvVxYtnCeFCxfR4aYKLJs0e1UWL5ynz5cZfDOsPHH84M1HA75NneYgPhw+fEQWLV4qLVq8IoEpUzrLkYhFf88DWCtnzjz6305DCZjnaiiP85kafoj6Atw7rvpCZmNOjpufqU3zucBSOXP6lGzcuF6uXr0ihQsXlYIPP3LLevnzz7OybMlCqVK1huTMeX90YFmrnmS+GXK6B5bjx46UNu08Aks1GjNPPhk5fIikDUontWrVjTHNXI3sBBKDm4OPgViwc8BurtkZBJaAea6GMiq+vlkFfAj1Bbh3XPWFzMacJEmSmPtjbnwysHS5du2aLF+2WHLlfkCff9LTju1b9YjMChWfiJ4SXrSYDiGV6Cnh6fX5LkeN+FRatmobc0q4Go2ZOVjGfD5MipcoLceOHZEGTz0jyZIl048BAAD+gcASMI8pe7AB9QUwj/piD58LLD3PWblt62Y9UrLyE1X1BUGSJk2ql6tva9U07gfz5JUiRYvri+7s27dX6tVvKNevX5epkyfKcy+8JGnSRF90J3PmLDq8PHv2jB6Z6XnRnV92bpP9+/fLUw2fcf42AABI/GgoAfNoKGED6gtgHvXFHj4XWJ46GSqrv1slSZMl06FksmTJpUbNWpI2bZAcO3pU1vzwrQQkCZCoyCg98lKNrnQFjD/9+L0cPvSHREZGSalHy8gjjxTRy8OvXZNlSxdJWNglfb6/qtVDJOvN6d/uVwn/7tuVEhiYSsqVr6jvAwCAxI+GEjCPhhI2oL4A5lFf7OFzgaXLsWNHZd/ePfpCOAAAAHeLhhIwj4YSNqC+AOZRX+zhs4Glmgb+159n5cGb56QEAAC4GzSUgHk0lLAB9QUwj/piD58NLAEAAOIDDSVgHg0lbEB9AcyjvtiDwBIAAPg1GkrAPBpK2ID6AphHfbEHgSV8Rv1KX/vMawFssXDNM7b8U2ExGkrAPBpK2ID6AphHfbEHgSV8BoElYB6BJWxAQwmYR0MJG1BfAPOoL/YgsITPILAEzCOwhA1oKAHzaChhA+oLYB71xR4ElvAZBJaAeQSWsAENJWAeDSVsQH0BzKO+2IPAEj6DwBIwj8ASNqChBMyjoYQNqC+AedQXexBYwmcQWALmEVjCBjSUgHk0lLAB9QUwj/piDwJL+AwCS8A8AkvYgIYSMI+GEjagvgDmUV/sQWAJn0FgCZhHYAkb0FAC5tFQwgbUF8A86os9CCzhMwgsAfMILGEDGkrAPBpK2ID6AphHfbEHgSV8BoElYB6BJWxAQwmYR0MJG1BfAPOoL/YgsITPILAEzCOwhA1oKAHzaChhA+oLYB71xR4ElvAZBJaAeQSWsAENJWAeDSVsQH0BzKO+2IPAEj6DwBIwj8ASNqChBMyjoYQNqC+AedQXexBYwmcQWALmEVjCBjSUgHk0lLAB9QUwj/piDwJL+AwCS8A8AkvYgIYSMI+GEjagvgDmUV/sQWAJAAD8Gg0lYB4NJWxAfQHMo77Yg8ASAAD4NRpKwDwaStiA+gKYR32xB4ElfEayfsl95rUAtoh497ot/1RYjIYSMI+GEjagvgDmUV/sQWAJn0FgCZhHYAkb0FAC5tFQwgbUF8A86os9CCzhMwgsAfMILGEDGkrAPBpK2ID6AphHfbEHgSV8BoElYB6BJWxAQwmYR0MJG1BfAPOoL/YgsITPILAEzCOwhA1oKAHzaChhA+oLYB71xR4ElvAZBJaAeQSWsAENJWAeDSVsQH0BzKO+2IPAEgAA+DUaSsA8GkrYgPoCmEd9sQeBJQAA8Gs0lIB5NJSwAfUFMI/6Yg8CS/gMCj5gHgUfNqC+AOZRX2AD6gtgHvXFHgSW8BkUfMA8Cj5sQH0BzKO+wAbUF8A86os9CCzhMyj4gHkUfNiA+gKYR32BDagvgHnUF3tYE1iuW/uTBAcHS/4CBe3ZuokMBR8wj4IPG1BfAPOoL7AB9QUwj/piD6sDy/Br12TZ0kUSFnZJoqJEqlYPkaxZs9mz9X0MBR8wj4IPG1BfAPOoL7AB9QUwj/piD78PLCMjI2Xtz2vk0KE/JEWKlBKUNp3UqlNPb+FVK5dJpszBUrJkaTlz5rQsX7pImjR7zZ6t72Mo+IB5FHzYgPoCmEd9gQ2oL4B51Bd7+H1g+esvO+TokSNOSBkRESHJkiXTt0eNGCotW7WT5MmT6/vTp06SGjXrSObgLPo+zKLgA+ZR8GED6gtgHvUFNqC+AOZRX+zh94Hl3t93y7atm6VBw2ckMDCVs2XDw8Nl3JiR0rZ9J2fZooXzpHDhIpInb37Z9esWZzkS1v8Kl3JuA7g3OObBH1FfgHuP+gJ/RH0B7j3qizn36pjn94GlcmD/Xtm+fZukTJlSSpd+TLJlz64Dy/FjR0qbdh6BZZGikidPPlm39htnOQAAAAAAAGCbsuWq3ZN/shWBpcv5c+dk/rzZUqt2PcmaLbuMGvGptGzVNuaU8JC6kjlz8M1nAAAAAAAAADDJ7wNL93NWKgsXzNXTvvPmK6AvupM5cxYpUbKUnD17RpYtWchFdwAAAAAAAIB7yO8Dy19+2S67ft0pyZIml8jIG3JfpkzyZNWakiRJEgm/dk2WLV0kYWGXJCpKpGr1EMmaNds93BwAAAAAAACA3fw+sHRZt/YnCQ4OlvwFCjrLAAAAAAAAAPgWawLLo0ePSOrUqSVTpsy+tQUAAAAAAAAAOKwJLAEAAAAAAAD4PgJLADEcPXpY1v38kz7na8SNCClfobLkyZNP/8zbeV/Vxa3W/PCdnDoVKpGRkZIhw31SM6ROjAteHT58ULZs3iQREdelYqUqkj17DudnAAD/F9/1Zc/uXbJ92xZnxYWFhUm27Dmkdp36zjIAgP+L7/qibNu6WXb/9qskSZpE0qQJ0j9LkSKF/69MwIcQWAKI4eTJUMmQIaMEBgbKhfPnZcb0yfJGmw76Z6tWLpNMmYOlZMnScubMaVm+dJE0afaaREVFybGjRyRX7gf045YvW6wDyWLFS+r76uJXe3b/JiG16klQUJBeBgCwS0LUFxfVbM6aOVVqhtSVjBnvc5YDAPxffNeX06dOysoVS+XFl5vri/WqYDNlykB57PFy/r8yAR9CYAnAK/XN4+hRn0m7Dl30/VEjhkrLVu0kefLk+v70qZOkRs06kjk4i77v8vNPP0jy5CmkzGNlJTw8XL6YOFaaNm+hP0QAABAf9cXdli2b5ErYZalQ8QlnGQDAPvFRX44dPSobN66Tpxs9p3+2ZfNGHXCWfvSxm48GYAKBJQCvVOFW3yqWLVdRB4/jxoyUtu07OT9ftHCeFC5cRPLkze8su3jxb5k3Z5Y0evYFSZMmrRw69IesXL5UsmXLLtfCr0naNEHyxJPVJFWqVM5zAAB2iY/64qJGV06aOEZeerm5BAZSWwDAZvFVX1atXKp/z/3355bff98jtWrXc0JPAGYQWAKI1dqf18jfF/6WmrXqSEBAgC7448eOlDbtPAp+kaLOOWLOnzsnixfPk2rVakm27Nn1sl27dsqhgwf1OcXU71GjYM6f+1OqVgvRPwcA2CW+6ovL73t+03VG/T4AgL3iq76o814uWbJQihQtpqeYq3NZVqt+a/0BkLAILAHcQhX7sLDLujC7GzXiU2nZqm3MKRUhdSVz5uDobybnzpZatepKcJasN58hsn/f77J7929Sr35Dff+vv/6UFcsWS+OXmt18BADAFvFZX1wWzp8jxUuWkty5H3SWAQDsEp/1ZevWzfo0I+riPYq+eOimjfL0M8/ffAQAEwgsAcRw9MgRWbd2jTz7/Ev6m0l36qTVmTNnkRIlS8nZs2dk2ZKF+qTVyqyvpsnjZctL7gdiNoxXr16RyV9OkCZNX9PTwHds3yZnz56WqtVqOo8BAPi/+K4vLiOGD5E3WndwruwKALBLfNcXNaJy//59zoALNWPs8KFDesYYAHMILAHE8MP338r+fXslXbr0zrJyFSpJzpz36+kRy5YukrCwSxIVJVK1eohkzZpNT7cY/tmgGKNbMmTMKNVrRH/D+ceBfbJhw1p9HphUqdJIjZq1OM8YAFgmIerLhQvnZe7XM+WV11rd/CkAwDYJUV/UlcFPnDgmSZMkk2TJk+vladP+c/5kAAmPwBIAAAAAAACAzyCwBAAAAAAAAOAzCCwBAAAAAAAA+AwCSwAAAAAAAAA+g8ASAAAAAAAAgM8gsAQAAAAAAADgMwgsAQAAAAAAAPgMAksAAAAAAAAAPoPAEgAAAAAAAIDPILAEAAAAAAAA4DMILAEAAAAAAAD4DAJLAAAAAAAAAD6DwBIAAAAAAACAzyCwBAAAAAAAAOAzCCwBAAAAAAAA+AwCSwAAAAAAAAA+g8ASAAAAAAAAgM8gsAQAAAAAAADgMwgsAQAAAAAAAPgMAksAAAAAAAAAPoPAEgAAAAAAAIDPILAEAAAAAAAA4DMILAEAAAAAAAD4DAJLAAAAAAAAAD6DwBIAAAAAAACAzyCwTAAXp89wbscl6MXGzm2YdXVnr9v6g4FFuzu3gYS2eV2o7NtzzrnvTanHs8tDhTI692GX1YdXy49HfvrXf3SVB6pIxdwVnPuAzSKjRMas/utfV0FAgMgbVe5z7gMAAODeILBMAKH16jm345J90SLntj+5dOmSzJg+VVq+/obP/rMuTEt+W68t/UvXndu+okuXTtKjR08JCAiI1/U8dcpkafziS5I0aVJnGUQmThgvzV95VWbN+koaNmwkKVOmTLDVMnrIVlk6/w/nvjetOpWQOg3zOffvtevXr8v0aVOkWfNXZc2aH+TokSPy0stNbutl3enj7wXXey4oKOhe/PlbfLjmQ+n7cz/nvjc9K/WU98q/69xPDK5cuSJfz54pTZo2TwwvN97MnzdPihQtIvny5XeWxeXUqZMycsRw6dmrj7PsTvTq9bEEpQ2SqlWrSZGiRZ3lph04sF8OHzokwcFZ5Ntvv5HLly/L+x8kzBeFEZEiJT/c59z3JmkSkW09Czj3IfH6ucPGfQ8AANwdAssEYDKwVOHgG61aSt9+n0ju3A84r+HD7u9L585dJUPG6FFYv//+u8yYMVXf3rd3nxR4KPrDeN069aX0o4/q2/Hl/LlzMmzYZ/LhRz2cZZ527Ngu58+fk8qVqzjLTDIRWN64cUOaNX1Z8hf4pwGtVrW6VKhYybl/N86cOa2bu39bz9OmTZFTJ09J5y5dnWVffTVdcuXKLeXLxxx1tXHjBvn99z3SpEkzZ9n7770jFStVlpCQWs4yb+52e+7bt09Gfz5S0qRNI5E3bkj27PdL02bNfCYYUt55u5v06fuJbNq4Qf44+Ie8+OLLN199/DMVWC5btky+X/2dpEyZQq6Fh0uxYsXk+ecb33VYffXqFenbp7cOT65evSrh4eGSLl065+fu5s2dK6VLl5ZcuXPr+//2+Nsx7LNP5fTpk5JEvf4okdp16srjj5d1fn4nLly4IPPnz5VmzV5xlrnec77CVGC5a9cumT37KwkISCI3bkRIvXoN5NFHyyToavj7779lyJCB0qNH3KPgN25YL0uXLtUByjPPPiv/+19h52dKfNW82zm2xXasvVPjxo6WChUrS6FChZxl7jxfR1RUlJw9e1aCg4NvPuLOqOO7Oq7da1u2bJZ9+/bKCy+8mOCvy3Rg6e3zWXzx3Cc87d9/QKZNm6xfh1K4cOEYx7U7cbufO1zUMbnDmx2d++5s3PcAAMDdIbBMACYDywXz50to6AkJSJJEWrX65xtvz8DSXft2bWX4iJHO/fh2Ox9oVVjy98WLUr9+A2eZSaYCyy6dO8mnnw1LkH9aXOtZBUC9e30sSZImkXbt3pTMmTPr5d4Cy969esqbHTs5QeH+/ftl8eJFEnrihHzSf4AOBeJyt9vzl507Zf36tc5oje+++1Z+/eUXr43OveAKLFWY1/2D9+SjHj0lWbJkCfJSTAWW7vtBRESEfPnFRAnOkvWOt5+Le2D5b0aOGCE1Q2pJ/vzxN0LU/Xj394UL8sknfaVN23Zy//25nMfcrtOnT8uECePl3Xffc5b5GlOBZdcuneXtd97RQUVkZKTezqlTp0nQ1XG7geV7776t97ewy5dl9OjP5a2333F+5um/1Lx/O7Z5O9beqX8LLP/tddwpG0Mj04Glt89n8SWufeLPP/+Ufn37SMdOnZzj4Pnz5yVDhgw3H3F34vrc4a5L544yeMinzn13Nu57AADg7hBYJgBTgaUaYfH+e2/Lxz37yHvvvSM9e/aWVKlS6ddwJ4Hl56NG6W/PVUP6WouWcuXKVZk9e6Zcv35NsmXLoT9oq1FQqikLTJVKBwIFChRwQibVaJ08eUoHOk2bRo+Oc/9Aq6bUnjhxQje7TZu9Ig899JD+oL1g4QLJkiWrvt+o0TOy9uefZOnSJTocy5s3rzR/5bV/Dcru1r0OLD/7dKicv3BeoqIiJWOG+9SgMLlw4byEXQ6TJk2bSuHCRXQjPGjgAD1SUwJE3nyzkx6F5moE4mocVq/+Vi5fDpOgoLRy6tQpee65F/Ty2AJLFRB89tlQ6d79I2fZiBHDpU7tOrJs+TKpXKmy/K9w9Ogl9ffq1asnefLk1fe7desiAwcOjnV7qlGbCxfM14282o9atGgpKVKk0M9z8Qws1b+5W9cu8tmw4Xpq4Jgxo+X8+b/0qLmmzV7VIdfKlSv0vpIyZaCUr1BBKlWqLJ8OHaKbMfXAFClSSsvXWzkjj2bPmiU7dmyVqCiRxx8vJ/Xq19fL1QgQ9Ry1X6YMDJROnbro9atGo4z+fJQeuaL+xuHDh2TM2PF6/54xY5o8/HAhKVGipP4d8e1eBJbKb7/9Jt+sWimvt2oln/TrK0mTJtPvPTU188jhwzJp0kSJjLohqVOlkbbt2uv3+KFDB2XixPESIAF6Pan1qAKk9evWytGjR+XZ557X/58wfpzez4PSpZeuXbvpwPLU6VBJlSqNVK9WXSIiruvHlS1XTqZMmeIEhWrk1d69v0vjxi/J9OlTZc/u3TpcrVGjpjxR5Un9GBfP450a8fbAAw9KhQoV5fixYzJevQaJ1P+uVq1aS5YsWbzuyyqwVMdTNTU3VWCgdOzU2XnP7d69W6ZO+VJSpEwpF85fkNp16ki1atX180+eDJVxY8fKjcgIuR5+XYoXL6HXQUIwFVi+/XY36dCho+TMmdP520pc7zdv28rbcnWqhW1bt0pgYCqpU7euPPRQQenQvp3kyZNHwsOvyQMPPKCPD561oFfPj6Vd+/Zy+PBh2bd3b5zr2rPmxVZr1Gi1NWvWSIcOb0poqNqWY+SD7h/Kmh++v+XY5s7bsTaufSW2mugKLNUxaPLkL533wfffr5aLFy9JUNo0MV5H9eo1YgS7nusxKCidnrqr3pu5cuWSl5s01Y9zcQ+NlixZIhs2rNXvZVX/W7RsJQ89VMBrDVKPX7/uZ0mWPPrUKrlz55YjR47o+qXec65jbGzrWd3+6acfZfGihfq1RkSES+EiRf1uhGVcn8+2bdsqc76erb/4Up+t1L5bqlRprzXP2/aJre66jBs3RgoVekRvD0/ejomqDkyZ/IXeLteuXZWKFStLrdq19XO8fe7wVl/Vey7HzePGq6++JlmzZtW3FRv3PQAAcHcILBOAqcDyl192ypbNm/X59b6ePVvSZ0ivmxjFs4F359m8xfVN+KefDpWGDZ+WjBkzxmiOVMMaElJb0mdIJ1OnTJFub7198xnev4E/fvy4zJgxXYcWniMD1NQ2FRK9+977OhhSt1WAUaxY8ZvPjl+mAkvPKeFvvfWOHqHkvs5HjRyhzyFWsWIl3Xx/8cVE+eijj28+I9qqlSt1o6+aB2+Ng7uPe3wknTp11kHcO++8JYMHD5UkSZLEGlju3btXflzzvbzW4nV9X51Drm+fXtKrd1/dwKxauUKPvlS8hTye21ON7ujbt7f06tVHUqdOrfdP1cA9+9xz+ucu7oGl+vnKFStk957d0rFjJ91wqWm9RYoU1YH68GGf6UBMnUtr0KAhMQIM9/W5besWmT9/nnzcs7esX79O1q1dK506d9GBfJ8+veTppxvp6aPuz1Eh6MWLF3XDN3bM5zqUrFT5Cf2cbl07y4CBg/V++cMP0eFB3bq3d57aO3UvAstr167pUPGBB/NIxYoVbxnd9tGHH0gndSzJkEGfb1I1u+pcp2q9dO7STbJnz67DqyGDB94SWL7VrasOldynQ3qOsHR/vBrR13/AQL2uJ3/5hZQqXVounD+vf/78C431e+D9996VHh/3dJp/xf149+efZ2XAgP7Svn0HPbJIjZBt9UZrvc/+tus3/WXMRz0+9rovxzbC0rWvuL9Wdd7Ot7p1kUGDh+rX+8H778jLTZrLww8/rNfR7NmzdNiZEEwFlurYoPaNkqVKRh/v06fXf9/b+00FVLFtK/WY2JZv375NNm3cKO07vOm8nz1HWLpqzcOFHtb3XdR7+6sZM6RY8WLStGlzvQ28ca95cdUadSwuW7asLF22TJo3ay4577//lmObJ2/H2rj2FRf3mug+wlLti3369NNf8KjXV7NmiP7ixP11uK+ndevW3rIe1Rcy9Rs0kAcfzKPve3IPjSZMGKePteq4qPbdiZMmxPgCS3GvQe6PV4Hqnj175I03Wut/Z8c3O8iw4SPk3Llzsa7nHDlyyqBBA3SAp84HrPaZI0eP+F1g6e3zmTpWftzjQ/1+UeGvqj2KCvG91Txv2yeuffO9d9/Sx+3YTmXh7Zjovs+qbd2z50fy7LPP69cT2+eO262vnmzc9wAAwN0hsEwApgJL9aGxdu26uvFXTfaI4dEfbpX/ElgePPiHPs+cGlVx7Ngxada8ueTPXyBGE6lGTQQGBkrlyk/oYCpvnrxSp05d/ffcP9Cq3zF37hw5dPCgREmUnPvrL+n3yYBbPmj/+OMa/TgVfihhYZelatXqOsRLCKYCS29Twj3Dshs3IqVWrehzRarQZtDgIbohnT59mly6eFGPvnyoYEF9jsnYGgd3anTQlxXquVUAAA4GSURBVF9MknduBi6jRo2U8uXL64Y8tsBSjYRUo+VcI4O+/WaVXA4Lc7aN+nu9eqvgMY3XkMdze/704xodvroupKJCpMGDBki79m/qRlpRTVGK5Cn061MjuNTUuTx580mbNm11yPlmh/aS8/5/RnZdunRRevbsIzOmT5PQkyelYcOGzuvw3IfbtmktAwcNlilTJkuZMmWcEZEqcFMjBtVoI/fnqIs+LFq0UNq176D/7pChnzrBgvuUcBW8/Lrr1xjn+oxPJgPLDRs26FFhKlwpU+ZxqVWrtg5t3d/nKnh++62uet9TIq5HSPYc2aV+/adk2GdDddOtuE8JdzW9T1atJp99OsQ5JrnEFVh+MWmilCxVSooWLSYffvi+fh1jx46R0BPHJU3atPrx58/9Je07dJTs2XPo+4o63qmRQpGRN+Tw4SPyZseOepv/9ddfMmhgf+nbr7/zWDV6b8DAQfr3xrYv325gqajRZ2pEdMoUKaXfJ32lf/+Berm/BJaKOob//PNPsmD+PHn55SZSomQpr+83NTIwtm21YMECr8vLlysf46IvnoGlq9Y8+WTVm4+IPj/l17NnSdVq1WTVqpXSrdtb8uOPP+ptmT//rRetca95cdUaNbpaBYtVqjzpbGPPY5u7uI613vaVzJmDY62J7oGlOsbly59fypR5TAfhPXv11SM9vQWWakq853rcvGmTLFw4X+o3eEqP3nP/gkfxFhoprveCtxrkGaB99dUM6dK1m36umoasRmqrL7tiW8/KiRPH9TlzFX89h6W3z2fqvXRg/35p2iz6olLugaW3mudt+8S1b6rt27FTl1vOcRrXMXH7tq0x9lkVRqugXJ33MrbPHWo06O3UV0827nsAAODuEFgmABOBpQoI2rRuLbkf+OccbYcOHpJ+n/TXjfx/CSzVCLb33+8u9913nw64ChR4SP/n3kS6h2xqZNzWrVtk3tyv9RSmLMHBzgda9YFaTRVTH85V46s+qH7Sf6AeqXbhwt/OB231QVcFpXd7Qvg75UuBpQoIr169pqfxKa7toYKdxx5/TEqXflSPRNy+fau+cm5sjYO7mTNnyPr16yV9+uiLmKjpiiqkVFMdYwss1QiLLVs2Olfl7dGju57SmjxF9HS/M6fP6FETVatV142xuqqsOiWA4mqcPLenCgVU4xIzsBwYo0lS3EdYqitFjxo1Qjd1yZMn1/upGm2nwktPKmCdNWumFClcNMaoUxc1+k+FaSpAeeyxx2I0VK4rUrs/x73pfrNDO/0606SJPlefe2CppjKePXNWnmrYUP8svpkMLD33A8UzLFLbbUD//no7uFNB5oD+nzjLYw8sq8rQIYOkd5+YF/ZQoU6NGiGxBpZ79+6T775dpUeUrV79nbz6Wgs9Mku9B+K6UIr78U6NSipeooQOoNTrVEG5Z3OuwjU1zT22ffnMmTN6uuTtBJZq9N/TjRrdDPOH6nBB8afA0kWN+FLbfOCgId7fb19+Eeu28rYN9ai7smWlWPESzjLPfdDzCx1lxPBhUr1GTSlYsKAeybZw4UJ1FRr9/lXhpif3mhdXrVH731czpunbajq4CvM9j23u4jrWettX/jhwINaa6B5YqiB06pTJ+gJkX8/+Wtq2a3fL64gRWMayHhVVIxYtXihnzpyVzp27OMuVuEKjf6tB7o9Xr3XKlC/17AFlwIBPdKipLqQT23pWteGPPw44y/0xsIzr85k6fYFaZ2q0seIeWHqred62j+c+4U6FiUWLFpWyZcs5y5S4jomukdCufXbDhvWyZ89ur4Gl+jzgrb66vniNjY37HgAAuDsElgnARGCpPhiqC6K4PvQqK5Yvlwt/n9cj5f5LYKl+PnjIUD0d7d8Cy5CQEGfkhmrQ1FWUGzRoKAP699MNrLoasfrwrqaVuzdnqsncsH69tGgZPQ1ZNcNqap1qoNS0QzW9SDWLCSUxBJYq4KtXv4E+N1VsgaU635VrPbtTjYIaEemaMqvWpQrhVEOipm56BlVqiqQ6F6FqONXt4cM+jfE7VQMzYfxY6fFxL1m4cIEeyVanTh39M1fI47k9XVPCe/fuq1/H7UwJV+bNmytXr1zRU45VwxWcOVg3+Yprn1C/R+1zqmEf0L+vDsTUOunTt58+99aBA/tl0sTxermasrZ+3To9NTeuKWvugaV6brp0GaTRM9HnA3MPLOfPmydZs2W9pQmML74WWCpqiqeaPui6GIhrO7z9Vjcduvzvf/+LNbBUTa/aF9u0bSt58/5zgZ2ZX83QVwgvV668vu8Z7KgRZTly5nJCTTVaV42eU6edUOd8i+3Y4H68U6Pkund/X59WQU1jV9vvjdZt9NRY9+mP3vZlNRXy3Xfekv4DBjl/x7WveL5WVwil3lOdOr4pb7/zrh5Rpq7Ou3jRgkQ/Jdz9Ih36qtvTp+rjgLf3m7dtFdfyjZs26SnV3qaExxZYquPRQwUf1qG0Oh5EXyX+lD6Nhee+objXPG+1Rm13dZ5mdZqDFSuWS9q0Qfpveh7b3MV1rN2+bVus+8quXb/FWhPV6GIV6KrzFyvqXLJZs2bR53dUV2b3fB3u6ym29eg6TirqS8h+/frHOIfw7YRG3mrQ7QSWyZIljXU9q9rQ8+OP9CkBMma8zy8Dy7g+n6l9dsiQwc6Uf3UcUiG7Ciy91Txv28dzn3B35Mhh+XToUH1Mcp0/Uo3YVPu1t2OiOr6poFltY/W3hwwepEcxq0DS9TfdP3fEVV/dTyXiycZ9DwAA3B0CywRgIrDs06e3NG3SVDf+LhcuXJCPPuyupyD/l8BSfdj+5puVkiowtVy8+Le+KECOHDlibSILFy4sY0aPkuTJU+iT8rds+bo+R5X6oKump6lRH6NGjtTntlIfvFOlTq3PT6iaw4ED+svlyxclW/ac0q5d+5vTDudLihTJJVmy5LqhSSimAkt1Dkt1sQGXfPnySbPmr8ZY595GWB784w/58stJ+qIW6uITj5Z5XIcr7s91rWfXuUvVCCEVlHTu0lXfd1GBgrqIyInQE7cElkqPjz7UF1hZsnixBKYKlJCQf8IBRYU5b731tqRKlVqGDh0sV8LC9G01ClH9rdi2p5pqrqaRqp45R477dVP1bxfdcYVFb739rg4Bxoz+XE6fOS0pkifX/8YKFStJz497SECSALkeHi5PNXxaj/5R6yRTpsx62qHaz15v9YZzZdTZs2bqixyoqxiULVvBuSiA+3p0DyxVmDB+/Hg5cfyYDilv3IjQYYz6vepvq8e4Rl/GN18MLPXFdSaM19smSZIAeaN1W71u1bTO8ePGyfXr4fqiOrlyP6gv0OUe6qkRVpMmTtDhiVp/3T/sIefO/SUDBwyQwFQp9VT0zJkyxQh2li9fJj+u+cEJU9Rzv5oxXbZs2SKpU6fSU2U9R215Hu/U9Nnf9/4uLVu2kmPHjurXqaaLq+OUCl/VBSZUsBnbvqyokXObN2+WNGlSS7du7+jfr/YVb4GlOkenCvTU1dbVPh4ZFSmZM2fRI+0SgolzWLre0+pchGrdqItnNWvWXP9bvb3fvG2ruJari/Hs3LFTAgNTSsVKlfU06NhqjXtgqUZ5qSn9YWFh+v2pRn+Hh4fr8526to07z5oXW61ZtGiRpEyZQgdH6t/e/YP35IPuH+nzLHoe25R/O9aq/SC2fUXNXIitJu7atUsmT/5CB1kq1FVBkloPo8eM0/c9j7HqAneu9RTbejx29Kg+LYdaP0WKFpNnn435ZdHthEbeatDtBJYquI9tPStqRoaa0q/+XWq7qXWuTiGhuL+u+GbqKuH/9vlMncbgm1WrdI27eOmi1K5VW+/D6pjkWfPUuZS9bR/PfcK1b7qofeirmdPk2rVwuRFxQx588EF92hNvx0R1fJs1a5akSxekg0lVW12hq7fPHd7qqxo5O23qVP271HvA9doVG/c9AABwdwgsE8Cl6dOd23FJ++KLzm2Yde2X2wtDUxb50Lntz5YtXaqngLuuYpvYuDdTCUVNY1SBrrqwRULZtC5U9u8559z3ptTj2eWhQrd+GQHfoKa9njp5Sp559tkEeUGrD6+WH4/+6Nz35oncVaRS7luvEvxfmXi/2U5dSOfY0WO3jEqPLwkZDP4XCfm6IqNExqz+07nvXYC0fvI+515CUtOqK1WqLI888oiz7F7x/EImoSTkNv4vfPV1AQBgMwJLAHpqorqyshpF6brYTGJiIkBR50Z88aWXJVOmTIlp1cAQdc7BgwcPSpKkSSVN6tR61KHnuej8hYn3m63U6MOVK1ZI6jRp9IhlNcIzIbRv10aPBFXncXW/WM+9okbbf/vtN3pU9mfDRtyrl5Hg1NRpNd3/RuQN/bfURaIaN34pwf/u7TAVWLLvAQCA20VgCUBznS8LsWP9AAAAAABgBoElAAAAAAAAAJ9BYAkAAAAAAADAZxBYAgAAAAAAAPAZBJYAAAAAAAAAfAaBJQAAAAAAAACfQWAJAAAAAAAAwGcQWAIAAAAAAADwGQSWAAAAAAAAAHwGgSUAAAAAAAAAn0FgCQAAAAAAAMBnEFgCAAAAAAAA8BkElgAAAAAAAAB8BoElAAAAAAAAAJ9BYAkAAAAAAADAZxBYAgAAAAAAAPAZBJYAAAAAAAAAfAaBJQAAAAAAAACfQWAJAAAAAAAAwGcQWAIAAAAAAADwGQSWAAAAAAAAAHwGgSUAAAAAAAAAn0FgCQAAAAAAAMBnEFgCAAAAAAAA8BkElgAAAAAAAAB8BoElAAAAAAAAAJ9BYAkAAAAAAADAZxBYAgAAAAAAAPAZ/wcolAHNB9ND+AAAABBkZUJHMkVDQjYzRUYzNzgzRDY2M2OP4MAAAAAASUVORK5CYII=" + } }, "metadata": {}, "output_type": "display_data" @@ -2753,22 +2839,29 @@ "cell_type": "code", "execution_count": 13, "id": "3b395fbd", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.219421Z", + "iopub.status.busy": "2026-07-13T22:00:12.219130Z", + "iopub.status.idle": "2026-07-13T22:00:12.236263Z", + "shell.execute_reply": "2026-07-13T22:00:12.235002Z" + } + }, "outputs": [ { "data": { "application/mercury+json": { - "model_id": "5971e8eb0b88489b844e79389b1aa454", + "model_id": "ffa89c9fcbcd417896eaba9fec38d96c", "position": "sidebar", "widget": "SelectWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "5971e8eb0b88489b844e79389b1aa454", + "model_id": "ffa89c9fcbcd417896eaba9fec38d96c", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -2777,17 +2870,17 @@ { "data": { "application/mercury+json": { - "model_id": "b9ff942d6df348acae9bab10a224f717", + "model_id": "f8456441f0ae4695ae97815b0b0aac84", "position": "sidebar", "widget": "SelectWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "b9ff942d6df348acae9bab10a224f717", + "model_id": "f8456441f0ae4695ae97815b0b0aac84", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -2796,17 +2889,17 @@ { "data": { "application/mercury+json": { - "model_id": "427872643bae4ee49202bef61c18b6dd", + "model_id": "f27fe4f9506d44b5948d86125bdf587b", "position": "sidebar", "widget": "CheckboxWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "427872643bae4ee49202bef61c18b6dd", + "model_id": "f27fe4f9506d44b5948d86125bdf587b", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -2831,7 +2924,14 @@ "cell_type": "code", "execution_count": 14, "id": "23756537", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.239635Z", + "iopub.status.busy": "2026-07-13T22:00:12.239284Z", + "iopub.status.idle": "2026-07-13T22:00:12.282614Z", + "shell.execute_reply": "2026-07-13T22:00:12.281166Z" + } + }, "outputs": [ { "data": { @@ -3131,7 +3231,14 @@ "cell_type": "code", "execution_count": 15, "id": "1ffaa74a", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.284671Z", + "iopub.status.busy": "2026-07-13T22:00:12.284479Z", + "iopub.status.idle": "2026-07-13T22:00:12.291405Z", + "shell.execute_reply": "2026-07-13T22:00:12.287871Z" + } + }, "outputs": [ { "name": "stdout", @@ -3161,16 +3268,18 @@ }, { "cell_type": "markdown", + "execution_count": null, "id": "b958f93d", "metadata": {}, + "outputs": [], "source": [ "\n", "\n", "## 5 · Corrected cost stack\n", "\n", "The pitched case vs the same case with the three missing costs added — plus the signed\n", - "contract mechanics: the **6-month ramp** (🟢 order form) means licences bill only half of\n", - "2026; PS bills on the **SOW milestones** (50/50 across 2026–27, $2.03M total vs the deck's\n", + "contract mechanics: licences are **invoiced in full from year 1** ($3.2M — the order-form\n", + "ramp gives free months operationally but the invoice is not netted down); PS bills on the **SOW milestones** (50/50 across 2026–27, $2.03M total vs the deck's\n", "$2.4M year-1 lump); and **managed services** ($411K/yr from MCX go-live) join the stack —\n", "an ongoing cost the deck's TCO never carried. **No existing-platform line appears** — current\n", "spend is excluded from this case per CTM's direction." @@ -3180,13 +3289,20 @@ "cell_type": "code", "execution_count": 16, "id": "ad880bda", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.293736Z", + "iopub.status.busy": "2026-07-13T22:00:12.293540Z", + "iopub.status.idle": "2026-07-13T22:00:12.481314Z", + "shell.execute_reply": "2026-07-13T22:00:12.480554Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Corrected programme cost: {2026: '$4.6M', 2027: '$7.7M', 2028: '$7.2M'} → 3-yr $19.5M\n", + "Corrected programme cost: {2026: '$6.2M', 2027: '$7.7M', 2028: '$7.2M'} → 3-yr $21.1M\n", "As pitched (deck): {2026: '$6.9M', 2027: '$4.3M', 2028: '$4.3M'} → 3-yr $15.5M (deck says $15.4M — rounding)\n" ] }, @@ -3220,10 +3336,10 @@ " \n", " \n", " CCaaS platform licences (contracted, ramp-adjusted)\n", - " 1,600,000\n", " 3,200,000\n", " 3,200,000\n", - " 8,000,000\n", + " 3,200,000\n", + " 9,600,000\n", " \n", " \n", " NTT PS + training (SOW billing milestones)\n", @@ -3262,10 +3378,10 @@ " \n", " \n", " TOTAL — corrected\n", - " 4,574,668\n", + " 6,174,668\n", " 7,696,892\n", " 7,248,154\n", - " 19,519,714\n", + " 21,119,714\n", " \n", " \n", "\n", @@ -3273,22 +3389,22 @@ ], "text/plain": [ " 2026 2027 \\\n", - "CCaaS platform licences (contracted, ramp-adjus... 1,600,000 3,200,000 \n", + "CCaaS platform licences (contracted, ramp-adjus... 3,200,000 3,200,000 \n", "NTT PS + training (SOW billing milestones) 1,179,723 1,012,723 \n", "NTT managed services (from MCX go-live) 68,486 410,918 \n", "AI token consumption 424,350 2,676,608 \n", "AI implementation + KB readiness 1,302,108 239,142 \n", "AI steady-state tuning 0 157,500 \n", - "TOTAL — corrected 4,574,668 7,696,892 \n", + "TOTAL — corrected 6,174,668 7,696,892 \n", "\n", " 2028 3-yr \n", - "CCaaS platform licences (contracted, ramp-adjus... 3,200,000 8,000,000 \n", + "CCaaS platform licences (contracted, ramp-adjus... 3,200,000 9,600,000 \n", "NTT PS + training (SOW billing milestones) 0 2,192,446 \n", "NTT managed services (from MCX go-live) 410,918 890,323 \n", "AI token consumption 3,479,736 6,580,694 \n", "AI implementation + KB readiness 0 1,541,250 \n", "AI steady-state tuning 157,500 315,000 \n", - "TOTAL — corrected 7,248,154 19,519,714 " + "TOTAL — corrected 7,248,154 21,119,714 " ] }, "metadata": {}, @@ -3491,7 +3607,14 @@ "cell_type": "code", "execution_count": 17, "id": "2e2b207c", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.483199Z", + "iopub.status.busy": "2026-07-13T22:00:12.482947Z", + "iopub.status.idle": "2026-07-13T22:00:12.604318Z", + "shell.execute_reply": "2026-07-13T22:00:12.603153Z" + } + }, "outputs": [ { "data": { @@ -3517,9 +3640,9 @@ "2028" ], "y": [ - 0, - 2700600, - 4663400 + 0.0, + 2700600.0, + 4663400.0 ] }, { @@ -3539,9 +3662,9 @@ "2028" ], "y": [ - 0, - 624800, - 2376200 + 0.0, + 624800.0, + 2376200.0 ] }, { @@ -3561,9 +3684,9 @@ "2028" ], "y": [ - 0, - 1379750, - 1591250 + 0.0, + 1379750.0, + 1591250.0 ] }, { @@ -3583,9 +3706,9 @@ "2028" ], "y": [ - 0, - 331650, - 482350 + 0.0, + 331650.0, + 482350.0 ] }, { @@ -3605,9 +3728,9 @@ "2028" ], "y": [ - 0, - 161400, - 364600 + 0.0, + 161400.0, + 364600.0 ] }, { @@ -3627,9 +3750,9 @@ "2028" ], "y": [ - 0, - 171850, - 195150 + 0.0, + 171850.0, + 195150.0 ] }, { @@ -3669,7 +3792,7 @@ "showarrow": false, "text": "$0K", "x": 0, - "y": 0, + "y": 0.0, "yshift": 12 }, { @@ -3680,7 +3803,7 @@ "showarrow": false, "text": "$5.4M", "x": 1, - "y": 5370050, + "y": 5370050.0, "yshift": 12 }, { @@ -3691,7 +3814,7 @@ "showarrow": false, "text": "$9.7M", "x": 2, - "y": 9672950, + "y": 9672950.0, "yshift": 12 }, { @@ -3703,7 +3826,7 @@ "text": "3-yr total $15.0M (verbatim)", "x": 2, "xshift": -40, - "y": 15043000, + "y": 15043000.0, "yshift": 16 } ], @@ -3810,7 +3933,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -3846,7 +3969,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -3870,7 +3993,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -3906,7 +4029,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -3933,7 +4056,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -3969,7 +4092,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -3984,7 +4107,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -4020,7 +4143,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -4176,7 +4299,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -4212,7 +4335,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -4303,7 +4426,7 @@ ], "sequential": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -4339,13 +4462,13 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], "sequentialminus": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -4381,7 +4504,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ] @@ -4537,8 +4660,7 @@ "zerolinewidth": 1.5 } } - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAABSwAAAHMCAYAAADf4OZ1AAAgAElEQVR4XuzdBZhV5drG8YfuRpGSDilpkO4ZUOzEABFb1M886vEYx65jgIFii4ENyMwwdEl3t5QIqCCd33W/w1ouFntvZpCYgf/v+84ls3at3mvd+3nfN9OePbv3GwAAAAAAAACkA5kILAEAAAAAAACkFwSWAAAAAAAAANINAksAAAAAAAAA6QaBJQAAAAAAAIB0g8ASAAAAAAAAQLpBYAkAAAAAAAAg3SCwBAAAAAAAAJBuEFgCAAAAAAAASDcILAEAAAAAAACkGwSWAAAAAAAAANINAksAAAAAAAAA6QaBJQAAAAAAAIB0g8ASAAAAAAAAQLpBYAkAAAAAAAAg3SCwBAAAAAAAAJBuEFgCAAAAAAAASDcILAEAAAAAAACkGwSWAAAAAAAAANINAksAAAAAAAAA6QaBJQAAAAAAAIB0g8ASAI6zffv2WebMmY/zp546WL8AAAAAkLERWAbs2bPHxo8fb8uXL7fChQtbs2bNrECBArZ161bLkSOHZc2a1X8ucDzdddddlpCQaO+887a1atXqmHz0a6+9bs8//7z997//tRtu6O5Px9G1fft2a9++g/XocYN169bNn36yeemll+2jjz6yO++80268sYetX7/e4uLi3bk0MTHB8ufPf9QXeffu3fb444/bvHnz7ZtvvrZMmTL5jwEAAAAAMo7jGlguXbrULrvsclu5cqXt3LnTsmfPbqeffro1atTIbr31VmvQoP4JW3O//fabXXTRxTZ79mx/Hr799hsrVKiwxcfHW6lSpWz8+HHuZnvgwIE2Y8YM69q1q5t+Mvn999/tjTfesO+//8Ftp0KFClnHjh3tscf+Y0WKFDmZFjVDadq0mds3v//+O2vduvURz/vkyVNs1KhRVr9+PWvRooU/XbSdx40bb3FxcfbVV1/6048W7U/atxS8rlmzxnLmzGnVqp1l553X2W699RbLli2b/9yT2aOPPmqvv/6GdevW1V577bWDFvW22263zz77zMqXL29Tp07J0IHb9dd3t2+//dZeeOEFu/nmm2zkyJF2/vkXuOUcMWK41alT58BSH7lbb73N+vXr5/bnoUOHusrKFi1a2qxZs6xXrzfs2muv9Z8LAAAAAMg4jmtgOXPmTGvePCUkqVy5sru5XL16tas4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8Ez/07//+OMPy5Y1qz39zFMHBZZLly6xpKQku+WWW/1pYb/8ssLefqu3PfPsC+5vzdMdt99q7/X9wLZv326PPPyQnV37bCtRoqS1b9/BPWfgwAEp/x3w4yHzKk8/9V+79rrr7Mwzy1jPO263Z597zvLmzecee/V/r1jHTuda+fLl7aMPP7AVK5bb3r177eyza9sVV17lnvN5v89swYL5ikGsYaNGLkjt3et1O+300233rl2WI2dOu+mmm61YsTPc8yOty0jrfffu3X7wOXr0KBv800DLniOH7dq502rUrGVLlixx21vLfV3Xrla9eg332tdff83atmlr1Wuk/A3gYASWAAAAAACk0ueff2ZDkpKseYsW1q1b90P6Idy6das9/NCD9trrvdzf/b/6yoqdUcxatGgZMTj0hCss1fT6/vvutYcf/reVLFXKVRc+8/RT9ryrSswcs9Jv8+bN9sQTj9nLL//P/R3pczdu3GD/fuRhe/iRR6106dL+9KA///jjkMBy7py59tHHH1j+fPmtcpUqdu655/lVp54pUybbiOHD7d777venqaqyd++37M8//7S33upld991jz3x5OP20kuvuHDxkUcesqefftbuvef/7OVX/ndIU/vbb7vVLa8C1b7v9bGqZ1Wzpk2budfqNa/871X76qsvXKVop07nuirPZ5952s6/4AKrUaOmPfnE43bDDT3cuhRVWP7w/Xf2r4cedn/PmDHdNdV+5tnn3d+e4LqMVGEZrNT85uuvLV/+fNahQ5zbDxSsvvra665Sde7cufbVl5/b40/8173uu2+/deH1RRddfOCdAAQRWAIAAAAAkAZq0vt+3/es2BlnuMBJ1X9//bXZChUqbA/+6yFXndfp3POsWrVq9p//PGL33fuA5S9QIGJw6AkHlpMnT7IRI0bYfYHQ73+vvGxNmzWzWrVqHRKcqYJPgd1v636z/bbfZs2caZ982s89Fu1zVyxfbj/88L39tWWLtW7d2po0aeo/JpECS4/WQVJSos2cMcMeDg3oo8By5IgRds+99/nTetxwvfV+821btWqlffPN165J+YcfvG9ly5a17Tt22p7du63z+efbgw/e7x4L9wl580032jt9UpZBIeGggQPsvvsfsJkzZ9jkSZNcc/MHH7jf8uXLZ9lzpISd6mu0Q4d4a9asecTAMtwk/PbbbnGBpcLS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" + } }, "metadata": {}, "output_type": "display_data" @@ -4568,8 +4690,10 @@ }, { "cell_type": "markdown", + "execution_count": null, "id": "95e3aa5a", "metadata": {}, + "outputs": [], "source": [ "\n", "\n", @@ -4578,14 +4702,21 @@ "The stack is the full programme cost — **excluding current spend** (no existing-platform line).\n", "The dashed grey line is the deck's cumulative cost case ($15.4M) for reference — the gap between\n", "the lines is what the pitch left out (tokens + AI implementation), net of the ramp credit and\n", - "contracted-rate savings it also left out." + "contracted-rate savings it also left out. Licences are invoiced in full from year 1." ] }, { "cell_type": "code", "execution_count": 18, "id": "c2c9418f", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.606835Z", + "iopub.status.busy": "2026-07-13T22:00:12.606508Z", + "iopub.status.idle": "2026-07-13T22:00:12.637762Z", + "shell.execute_reply": "2026-07-13T22:00:12.636921Z" + } + }, "outputs": [ { "data": { @@ -4611,9 +4742,9 @@ "2028" ], "y": [ - 1600000, - 3200000, - 3200000 + 3200000.0, + 3200000.0, + 3200000.0 ] }, { @@ -4635,7 +4766,7 @@ "y": [ 1179723.24, 1012723.24, - 0 + 0.0 ] }, { @@ -4677,9 +4808,9 @@ "2028" ], "y": [ - 424350, - 2676608, - 3479736 + 424350.0, + 2676608.0, + 3479736.0 ] }, { @@ -4701,7 +4832,7 @@ "y": [ 1302107.96532141, 239142.03467859002, - 0 + 0.0 ] }, { @@ -4721,9 +4852,9 @@ "2028" ], "y": [ - 0, - 157500, - 157500 + 0.0, + 157500.0, + 157500.0 ] }, { @@ -4748,7 +4879,7 @@ "2028" ], "y": { - "bdata": "A5a95nJzUUGQwvXo+GdnQa5H4RqOnXJB", + "bdata": "BJa95vKNV0GQwvXoOHVqQa5H4RouJHRB", "dtype": "f8" } }, @@ -4788,9 +4919,9 @@ "size": 12 }, "showarrow": false, - "text": "$4.6M", + "text": "$6.2M", "x": 0, - "y": 4574667.60532141, + "y": 6174667.605321411, "yshift": 12 }, { @@ -4821,10 +4952,10 @@ "size": 12 }, "showarrow": false, - "text": "3-yr $19.5M — $4.1M above the pitch", + "text": "3-yr $21.1M — $5.7M above the pitch", "x": 2, "xshift": -70, - "y": 19519713.68, + "y": 21119713.68, "yshift": 18 } ], @@ -4931,7 +5062,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -4967,7 +5098,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -4991,7 +5122,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -5027,7 +5158,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -5054,7 +5185,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -5090,7 +5221,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -5105,7 +5236,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -5141,7 +5272,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -5297,7 +5428,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -5333,7 +5464,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -5424,7 +5555,7 @@ ], "sequential": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -5460,13 +5591,13 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], "sequentialminus": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -5502,7 +5633,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ] @@ -5658,8 +5789,7 @@ "zerolinewidth": 1.5 } } - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAABSwAAAH0CAYAAAA3yWO1AAAgAElEQVR4XuzdB3gU1RoG4D8hhB46SAm9hJpCR4r0qnTpAgKKCvbutfeOig2kCIJ0FEF6lyYlhV5Ch4D0DoEk9/n+ZMbJMLvZQIAFv/e595Hs7E49074554zP1atXEoSIiIiIiIiIiIjIC/gwsCQiIiIiIiIiIiJvwcCSiIiIiIiIiIiIvAYDSyIiIiIiIiIiIvIaDCyJiIiIiIiIiIjIazCwJCIiIiIiIiIiIq/BwJKIiIiIiIiIiIi8BgNLIiIiIiIiIiIi8hoMLImIiIiIiIiIiMhrMLAkIiIiIiIiIiIir8HAkoiIiIiIiIiIiLwGA0siIiIiIiIiIiLyGgwsiYiIiIiIiIiIyGswsCQiIiIiIiIiIiKvwcCSiIiIiIiIiIiIvAYDSyIiIiIiIiIiIvIaDCyJiIiIiIiIiIjIazCwJCIiIiIiIiIiIq/BwJKIiIiIiIiIiIi8BgNLIiIiIiIiIiIi8hoMLImIiIiIiIiIiMhrMLAkIiIiIiIiIiIir8HAkohuuq5du8nq1atl0qRJUqVKmNvpjRo1Sr777ntp166dvPLKy+bn1yutx3ejli37S3r27ClNmjSRYcOGmp/favPmzZM33nhTypcvL8OH/3SrJ09ERERERETk0i0NLPfs2SN9+/aVvXv3yenTpyUhIUHuueceqVmzpgwc+ISEhISYM0Z3hhkzZkhkZKT06tVLChcufGfMtMXWrVtl8OCvZMGCBXLy5EkJDAyUHj16yNNPPyXp0qUzv0fX78qVK5I3bz7d399991158slBsm/fPvnzz1mSOXMmeeihh8zvwssvvyzff/+DPP/8c/L666+bn7uT1uO7md5//3355JNPJUuWLHLo0EHz81tt+PAR8uyzz8oDDzwgY8aMvtWTVxcuXJApU6bI3r175X//+99tmQciIiIiIiLyPrc0sIyKipK6devpWvD19dX/xsfH63/9/Pxk4sQJ0qhRI/2b7gxBQeUkJiZGli1bKpUrV74zZtri7bffli+++FLLX/bs2eX48eP6+YsvviCvvfZa0rfoRo0dO1bWrl2roVTu3Lnl559/lieffEpatmwpv/46zvweXE/AmNbju5mOHDki77//gdSrV1c6duxofn6reUNgGR0dLWFhVSQgIED27993q1cBEREREREReanbFlieOnVSw8odO3bIU089JatWrZZKlSrJX38t89JVRU7u9MAS4RFqVyI48vf3l6+//kZDLdT83bZtq7mclLbSOmBM6/H9FzCwJCIiIiIiIm912wLL06dPmetk0aJF0rZtO/33iRPH5cCBA/LFF1/I33+v0X9fvXpV6tevL+PH/6rfQfPPt956W3+H5qbVq1eXN954PVmT8ri4OPnmmyEybtw4bYqO5pcFCxaU4OBg+e67b/U76Etu6NChsmnTJjl48KBkypRJBg0aJM8996zWBPv99+kaaGXIkEGqVq0qH3zwvpQrV05/u2XLFnn33ff0v//884/OY7169aRfv74yatTPsmzZMq1FWqdOHRk8+EvJly+f/u6PP/6QoUOHya5du+To0aOSOXNm6dSpoy4D5iUqaoPWNurc+UF56623tOafYenSpfLBBx9IeHiEfueBB+7X72TLls38jt2aNWu1Ceq6des0IK5QobyMGDHCbL7911/L5cMPP5D168N1HTVr1kzeeutNyZs3rw5HM140mUY/gFhHqB0XFhZmhkJGYGm1fv06KVmypPm3FYIlhEdY/gIFCki3bt10fWM5sS5r1qyl623v3j26jPDDDz/KSy+9JI0bN5YpUybrZymtC3fb1h2jxhe+f/hw8uWCn34aLs8995yEhobI4sWLzc8feKCNLFmyRL755muzSTICoR9++EHLH5qaP/zww/LEE4+Lj4+PDp8wYYJ8/vkXcujQIS0/ZcuWkRdeeEFat26tw1G2sYwY7759++XUqVNSrFgxmTNntq6vN954Q2bMmClnz5411+VLL72ov71ZjG2E5vIHDx5IWk+HpWzZIJ3vsWN/0e99+eVg3R7oN3LUqJFy7711ZOPGjfLbb9OkQYMGZsBo9eCDD2qfjkbAiND44sWLui+Hhobq/ueqFm9ajS+lbWZ16dIleeqpp2XDhg26D2A7BAUFae1cbLM//pghZ86ckYoVK2iNyho1quvv0I1C9+49pGbNGjJnzhz9DF0T/O9/r8uKFSt0WkWLFpXXX/+ftGjRIsV9EFLaH2D58hXy7rvvSEREpOTMmVPy5cur/06pSfj48ePl22+/k+3bt+sxAse00aN/1mFYB5jupEmT5cSJE1K2bFntTqF9+/ZJv3a/bMb+ZoWyvHXrFo+Wm4iIiIiIiO5OXhFY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ueQS3X//D7VgwQLnJf7oR/+mr3/96zaQ9HhqnONvZsLJ1157zW6XkJaWZo9deeVVikYjuuWWW/S5z92i1177kx3uc/3112nXrt164YUX7KAfAAAATD8ElgCA82LD+pfe8nMnJnJnuMcG38zJn++sTRemPbW1tcW2epug0gwdOd7y5QVjrd5enwoLC23rKjCTmT0sf/CDH+j++3+klStXasOG9c5+kx/60Id04ECXGhrqT/oW9Pb2auXKQl177bW6777vO8cvvPB9thL56aefslWaeXl52rhxo5qbm/S9731PDz74kI4cOew8HwAAANMHgSUA4IyZ1ub+/rDC4T7b1l1UtEqJiWOBxMls7WhTckrKeZ/IfTaYKcbB8b0ozYTi46tFU1JStLqi0oaUptU7N/fUE8uBmeqf//mfdd99P7CB4pIlS+wWCWYK+Be+cJv+5V/+xXnZhw8ftoHmxF6Xv//97/Xxj3/CBpMm4Jxg9qqsqKjQE0/8TN/85jf13e9+z04hf+qpJ21V5733fkd79uxWZmam8z0AgJnjpZdespX1ppp+1qxZM+eFAbAILAEA70h392H19nQrYtq4oyak7HXWJlRUrlFmZrbzeCbasX27DSiDwTpt3rxFo6Ojzss0oaQZ+GGqKCsrq5SamuqsAfGisbFRd9xxp50MnpOTbcNKU225bdtWG0i+8sor+shHrtGDDz6gT3ziE/ZtMX+PiotL7PYITU2N9tjENPCNG9s1f/4bVdfLli23g3jM3pdmv0rTNn777f9iW8/vuutu3X777W/5HgDAzGA6WG6//Q49+uijuvXWz9tfWF188cX6u7/7e/3mN7+Z9CLNv8O6ug44j43XXltvrxn19Q2aO3euvva1r+pTn/qUXXvkkUf0pS99WXfeeaduu+3W8e+Q/aX0RRd9QJ/97M26++67neMAzg0CSwDAO9La4ld391HnsZGSmmancrszxlq5Z8+eaysLZxLT6m0ClIlKyoMHD056eabV1Uz09vq8WrFipXMciFfr12/Q1772NTt8Z3h42P4dueuub9uQ0Xj44Uf05S9/WX/848uqqXlj/8pLL71ULpfbDtExbrzxJr344ou2WvJ4eXlzbJu42RfzzUw4aio6zdYMZusFAMDMMTAwoDVr1tpfgpWXl2nv3k77y7GHHnpQzz//vDo6ttoX29vbY3/htXbt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" + } }, "metadata": {}, "output_type": "display_data" @@ -5694,7 +5824,14 @@ "cell_type": "code", "execution_count": 19, "id": "82335f50", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.640436Z", + "iopub.status.busy": "2026-07-13T22:00:12.640176Z", + "iopub.status.idle": "2026-07-13T22:00:12.666239Z", + "shell.execute_reply": "2026-07-13T22:00:12.665328Z" + } + }, "outputs": [ { "data": { @@ -5720,9 +5857,9 @@ "2028" ], "y": [ - 6867000, - 4300000, - 4300000 + 6867000.0, + 4300000.0, + 4300000.0 ] }, { @@ -5742,7 +5879,7 @@ "2028" ], "y": [ - 4574667.60532141, + 6174667.605321411, 7696891.67467859, 7248154.4 ] @@ -5756,10 +5893,10 @@ "size": 12 }, "showarrow": false, - "text": "−$2.3M", + "text": "−$692K", "x": 0, "xshift": 16, - "y": 4574667.60532141, + "y": 6174667.605321411, "yshift": 12 }, { @@ -5891,7 +6028,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -5927,7 +6064,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -5951,7 +6088,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -5987,7 +6124,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -6014,7 +6151,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -6050,7 +6187,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -6065,7 +6202,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -6101,7 +6238,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -6257,7 +6394,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -6293,7 +6430,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -6384,7 +6521,7 @@ ], "sequential": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -6420,13 +6557,13 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], "sequentialminus": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -6462,7 +6599,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ] @@ -6618,8 +6755,7 @@ "zerolinewidth": 1.5 } } - }, - "image/png": "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mdp2S/JJ3wEAAACgZVJYLgApC8t33nknDj7owDj5Jz+Nvn1XqL2Gf8ecOXNiypQp0b179/jb3x6OqVPfjC9+8b9r98/vrbfeijPPPC2OP/7HtX2f1bHfPTpOOvmn0aZNm9q+wi8uvyzWXGutGDRo3dq+whW/+kWsvfagGLjmmrV9VVx66SWx0UYbx+c+N6C27/777o3xz4+PPfbYq7avuaUsLJ977u9x5ZW/Kr8ThQEDBsS++3597itZ8H52ztlx+LeO+MxP9EnfAQAAAKBlUlguACkLy+uvuy5eeeXlaNW6dRx00MG11/Cf+tMf74i33n47dtjhf2r75regCssZM2bESScOjxOGn1jb16Q5C8vCD39wXPzo+OHRtm3b2r7mlKqwfP311+MnJ58URxx5ZPTps3z53FOnTo2lllpq7itZ8L7z7SPijDPP/sxP9HHfAQAAAKBbkf+yAAAJXUlEQVTlUlguAKkKy2JF5PeP+26cMPykOO64Y2P48BOjU6dO5f5LLr4wXn11UlkC7bPPvrF8376113fjjWPK1YVt27aL2bNnxW67fa08XLq+gCwKy+tvuD569OgZq666auy0084xduz9cf11o6J9+47l47feenAcPmxo9OvXL2bM+CBWWGGFOPCbB0erVq3i3XffjYsuujCmTn0jYk7EPvvuXx7GXaz+u/DnF5SrNzt06BgvvDAhLrp4xDxl1V/G3h8vvjgxdt5ll/K9XHXlyHj00UeiU+fOMfXNN2P//b9RFpYvTJgQl19+WcyeMys6d1osDhs6LLp06RITJ06MS0dcEnPmzI4uSywZRx11dK2wXG211eO0006Nr351p/Lw8F//+spYffU1Yp11BtWevzmlKiwvueSiWGON/4pNN/1C7bmb/OOll2JE8XnE7GjTpm0cdNAh0aNHj3jmmWdj5BW/iDZt28bKK60c62+w0Tzbe+61d9x7z91x8803lb/T/v37x35fP6C8Pf93YZdddo1hQw+LZZdbrnzO/fc/IBZffPF/+zsAAAAAtFwKywUgVWFZlHjjHnigPP/f7665JpZcasnYcsutyhWXI6+4Io4+5ru111SvfrXha69NjuEnnBA/+ekpMXv27HkKy/oVlq+/PiV++pOTy1WPnTt3LvfNv8Ly7LPOjMGDt4nV11i9LNCK5xg4cM3yOc792TnluTEvvujnZUG4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" + } }, "metadata": {}, "output_type": "display_data" @@ -6662,22 +6798,29 @@ "cell_type": "code", "execution_count": 20, "id": "de7679d8", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.669513Z", + "iopub.status.busy": "2026-07-13T22:00:12.669023Z", + "iopub.status.idle": "2026-07-13T22:00:12.677791Z", + "shell.execute_reply": "2026-07-13T22:00:12.676762Z" + } + }, "outputs": [ { "data": { "application/mercury+json": { - "model_id": "aad65db253294eddbecef4224a146196", + "model_id": "7d6b41e9a308492588bab31ad47834e7", "position": "sidebar", "widget": "SelectWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "aad65db253294eddbecef4224a146196", + "model_id": "7d6b41e9a308492588bab31ad47834e7", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -6696,13 +6839,20 @@ "cell_type": "code", "execution_count": 21, "id": "08433116", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.680244Z", + "iopub.status.busy": "2026-07-13T22:00:12.680025Z", + "iopub.status.idle": "2026-07-13T22:00:12.685685Z", + "shell.execute_reply": "2026-07-13T22:00:12.684194Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "corrected: net by year {2026: '-$4.6M', 2027: '-$2.3M', 2028: '$2.4M'}\n", + "corrected: net by year {2026: '-$6.2M', 2027: '-$2.3M', 2028: '$2.4M'}\n", "pitched: net by year {2026: '-$6.9M', 2027: '$1.1M', 2028: '$5.4M'}\n" ] } @@ -6733,7 +6883,14 @@ "cell_type": "code", "execution_count": 22, "id": "04c43658", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.687540Z", + "iopub.status.busy": "2026-07-13T22:00:12.687366Z", + "iopub.status.idle": "2026-07-13T22:00:12.714912Z", + "shell.execute_reply": "2026-07-13T22:00:12.713701Z" + } + }, "outputs": [ { "data": { @@ -6759,9 +6916,9 @@ "2028" ], "y": [ - 0, - 5370050, - 9672950 + 0.0, + 5370050.0, + 9672950.0 ] }, { @@ -6781,7 +6938,7 @@ "2028" ], "y": [ - -4574667.60532141, + -6174667.605321411, -7696891.67467859, -7248154.4 ] @@ -6808,7 +6965,7 @@ "2028" ], "y": { - "bdata": "A5a95nJzUcEfhetRwVNawbkehWvKE1HB", + "bdata": "BJa95vKNV8GQwvWoIDdgwboehWtKLlfB", "dtype": "f8" } } @@ -6821,9 +6978,9 @@ "size": 12 }, "showarrow": false, - "text": "-$4.6M", + "text": "-$6.2M", "x": 0, - "y": -4574667.60532141, + "y": -6174667.605321411, "yshift": -14 }, { @@ -6832,9 +6989,9 @@ "size": 12 }, "showarrow": false, - "text": "-$6.9M", + "text": "-$8.5M", "x": 1, - "y": -6901509.28, + "y": -8501509.280000001, "yshift": -14 }, { @@ -6843,9 +7000,9 @@ "size": 12 }, "showarrow": false, - "text": "-$4.5M", + "text": "-$6.1M", "x": 2, - "y": -4476713.680000001, + "y": -6076713.680000002, "yshift": -14 }, { @@ -6858,7 +7015,7 @@ "size": 12 }, "showarrow": false, - "text": "3-yr net -$4.5M · ROI -23%
NPV@13.5% -$4.2M · payback beyond 2028", + "text": "3-yr net -$6.1M · ROI -29%
NPV@13.5% -$5.6M · payback beyond 2028", "x": 0.01, "xref": "paper", "y": 0.98, @@ -6968,7 +7125,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -7004,7 +7161,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -7028,7 +7185,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -7064,7 +7221,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -7091,7 +7248,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -7127,7 +7284,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -7142,7 +7299,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -7178,7 +7335,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -7334,7 +7491,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -7370,7 +7527,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -7461,7 +7618,7 @@ ], "sequential": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -7497,13 +7654,13 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], "sequentialminus": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -7539,7 +7696,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ] @@ -7695,8 +7852,7 @@ "zerolinewidth": 1.5 } } - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAABSwAAAH0CAYAAAA3yWO1AAAgAElEQVR4XuzdBXQU5xoG4BcnOAR3KO7uxd3d3d1pC7TFiktxC+7uEtzd3R0S3CFI5J7vC7N3WTabpNDspnmfc+9hd3Z2duafme3ZN9///6E8PT/7gIiIiIiIiIiIiMgBhGJgSURERERERERERI6CgSURERERERERERE5DAaWRERERERERERE5DAYWBIREREREREREZHDYGBJREREREREREREDoOBJRERERERERERETkMBpZERERERERERETkMBhYEhERERERERERkcNgYElEREREREREREQOg4ElEREREREREREROQwGlkREREREREREROQwGFgSERERERERERGRw2BgSURERERERERERA6DgSURERERERERERE5DAaWRERERERERERE5DAYWBIREREREREREZHDYGBJREREREREREREDoOBJRERERERERERETkMBpZERERERERERETkMBhYEhERERERERERkcNgYElERD+Mj48P3r17hyhRopiWEREREREREQUGA0sH4ebmhkaNGuHx4yc4d+6s1b3q0qULXF23YNq0qShatKhp+Y+2b99+3ZdSpUrBxWW6aTkFvVmzZmPixImoWbMG+vTpE/Q7YMPLly9x9OhRPHz4EEmTJkWhQoUQNmxYvHr1CtGjRzet54iePHmCMmXKIkKECNiyxRXRokVzxN0MdkaNGo1Ro0ahQ4f2+OOPP4Ld/hMREREREZFjsEtgKdU3U6ZMxerVq3H9+nUNDZInT47y5cujU6eOiBw5smO0jh/u3r2LTZs2I1IkJzRu3Ni0/HtcuXIFefLkRaxYsXDr1k3TcnMFCxbC+fPnsWbNahQrVsy0/EcbPHgwRowYqefBze2BaTkFvd9++03vlZ49ezhUAHTgwEG99p8+faqNEiZMGNy9ewcLFy7CL7/8grp162qw/v79e6xcuRJ37tzB77//HvQN6Ic9e/agcuUq+nj37l3Inj37l1dCtu89Xz179oSLywy7Xq/fewxERERERERkf0EeWD5+/FiDgkuXLn1z9OHDh8f169ccvjpr7ty56Ny5iwasixcvMu3/93CkwPLRo0cYPHgIChf+GTVr1jTtIwU9Rw0sc+bMpX9sqFChAsqUKa3dgJs2bYru3btj5sxZyJo1K/bu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OI1y7UngJlWFJUuW0O8CYW0fAhJYin+ybWvH59f5kmtP3rdp02YNCOUak+9l+QOTi8t0/SOKtI2ch6VLl6Fq1SraXduSrfYz7jtb3/3yxx0JZ48fP673v4SQefLkwYAB/fUPE8KvY5A2ISIiIiIiIsdnl8CSiIiIiIiIiIiIyBoGlkREREREREREROQwGFgSERERERERERGRw2BgSURERERERERERA6DgSURERERERERERE5DAaWRERERERERERE5DAYWBIREREREREREZHDYGBJREREREREREREDoOBJRERERERERERETkMBpZERERERERERETkMBhYEhERERERERERkcNgYEkhzuNHD/HwoRuiRImKlD+lDnHHT0RERERERETkyP4TgeX79+9x5PABFCteym5tvXHDWlSoWOWbz7916wbOnD6FqtVqmpZ9j/37diNLluyIFj26admPtm3rZuTNW0A/Y8nieShcpCQSJkxoev1HC4pjMly/fhVHDu1H5izZEC5ceKRKnRarVi5FjZp1ETZsWNN6QUkC1CtXLuHnwsXw4cMHzJvjgpatOyB06ND/eDe8vb3hunkDXr96qdupbsfjC678uqcdyY++P4P63iciIiIiIiKyJkgDyxPHj+LWzRuoXrPOV2HMpAl/o0OnbqbngfXq1Uts3rgOdes3Ni37N23dsgkFCxVB5MiRTcumTZmANu06mZ4bvLy8NFCNGjWqadn3WL50EYqXLA1n59imZT/asiULUKpMecSMGQuvX79C1KjRECpUKNPrP1pQHJNh/brVyJY9J5IkSWpadvnSBaRLnxFubm64c/sm8hcoZHotKNy7dwfnzp5B+QqV9eNevnyBGDFiftdHX7l8EXdu30bpsuVNy/5tr1+9wq5d2+Hx/h0+f/6MNGnTI2++AqbXJZi+ffsmfLx9kDN3HmTIkFmXnz51ApcuntdrTL4XjGvv+fNn2Oq68cu75V7yxNu376zeZ98rMPd0QO3csRXubvcRJkxY3Xdn57goVLgookSJosd77OhhNGrS4qt7S4LmubNd9B5PliyFabk4c/okokWLhhQpU5mW/ej7M6jvfSIiIiIiIiJrgjywPHXyOJImS4HSZcqZdiK4BZYL5s9Clao1NSgwfG+4EVBBEe6ZhxZBISiOybB82SJkyZINUaNFRySnSIgRMyYePXRHvPgJ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JRERERERERERETkMBpZERERERERERETkMBhYEhERERERERERkcNgYElEREREREREREQOg4ElEREREREREREROQwGlkREREREREREROQwGFgSERERERERERGRw2BgSURERERERERERA6DgSURERERERERERE5DAaWRERERERERERE5DAYWBIREREREREREZHDYGBJREREREREREREDoOBJRERERERERERETkMBpZERERERERERETkMBhYEhERERERERERkcMIFoHl8qWLULlKdUSIGNFhGs7Sg/s3TY+JKPhJlDhl8NtpIiIiIiIiov+gYB1Yvn//HqtXLkHefAWRKnVa0+m5euUSjh09BB8fIHGSpCharKQuf/v2DWa6TEHzFm0RNVq0L2v72uK6EVGiREHBQkVMywJDAksGHkTBE+9fIiIiIiIiIsfh0IGlBIz79+3Bo4fuiBotOpIkSYrcefJp6507exoXL5yDD3yQK1deU2D5+vUrrFi2GA0bN0f48OGxft1qpE2XHmnSpIO7uztWr1yKFCl/QrnylUxn4cmTx1i5fDFSpEiFMuUqmJYHBgMPouCL9y8RERERERGR43DowHLzpvVInDgJMmfJpi3m6emJsGHD6uNXr14iWrTo2L7NFSlSpDQFlqdOHsebN69RuEhxfX7r1g2cO3tGu5TfuHENt2/dwMOH7ihbrhKcnWPrOmtWLcdPqVLj2rWrqF6jti4LLAYeRMEX718iIiIiIiIix+HQgeWO7VsQJnRoFC5aAqFDh7baatu2bv4qsNyze4cGmdlz5NLnz54+gavrBjRo2Aznz53RMDNu3Hi4fPkSKlSsotWbhw7uR4lSZbB+7UrUb9hM3+fmdlv/DSgfb+//XJfwT58+oWGDeujZ6xfkyZPXdKxE/zUSWIby4zuGiIiIiIiIKKRKmDC5XQ7doQNLb29vrZi8cf0q4sSJi9x5C+g4k+asB5YxkD1HTn0ugeUW1w0aRB4/dgShQoVCzlx5sHD+LFSoWA179+5Cnjz5EcvZGfPnzUSLlu30ffLZgeHudvs/FVhKNeu2rVsxe/ZM5MqVG3ny5kXhwkW+Co63uLpi5kwXNGzUGJUrVzEtN7Rr2wbPnj01Pa9XvwGqVasON7cH6NqlM3Llzo1ffvnN9LoEpB3at0W0aNEwesxY03JHIPu2fNlS7N27Fx8+eCBd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" + } }, "metadata": {}, "output_type": "display_data" @@ -7730,13 +7886,20 @@ "cell_type": "code", "execution_count": 23, "id": "a8c9584e", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.717839Z", + "iopub.status.busy": "2026-07-13T22:00:12.717626Z", + "iopub.status.idle": "2026-07-13T22:00:12.732320Z", + "shell.execute_reply": "2026-07-13T22:00:12.731299Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "The missed costs move the 3-yr case by $4.1M (-$424K pitched → -$4.5M corrected).\n" + "The missed costs move the 3-yr case by $5.7M (-$424K pitched → -$6.1M corrected).\n" ] }, { @@ -7773,27 +7936,27 @@ " \n", " 3-yr incremental cost\n", " $15.5M\n", - " $19.5M\n", + " $21.1M\n", " \n", " \n", " 3-yr net\n", " -$424K\n", - " -$4.5M\n", + " -$6.1M\n", " \n", " \n", " ROI (net ÷ incremental cost)\n", " -3%\n", - " -23%\n", + " -29%\n", " \n", " \n", " NPV @ 13.5% (deck rate)\n", " -$1.5M\n", - " -$4.2M\n", + " -$5.6M\n", " \n", " \n", " NPV @ 8.0% (CTM treasury)\n", " -$1.2M\n", - " -$4.3M\n", + " -$5.8M\n", " \n", " \n", " Payback\n", @@ -7807,11 +7970,11 @@ "text/plain": [ " As pitched (deck) Corrected\n", "3-yr benefits $15.0M $15.0M\n", - "3-yr incremental cost $15.5M $19.5M\n", - "3-yr net -$424K -$4.5M\n", - "ROI (net ÷ incremental cost) -3% -23%\n", - "NPV @ 13.5% (deck rate) -$1.5M -$4.2M\n", - "NPV @ 8.0% (CTM treasury) -$1.2M -$4.3M\n", + "3-yr incremental cost $15.5M $21.1M\n", + "3-yr net -$424K -$6.1M\n", + "ROI (net ÷ incremental cost) -3% -29%\n", + "NPV @ 13.5% (deck rate) -$1.5M -$5.6M\n", + "NPV @ 8.0% (CTM treasury) -$1.2M -$5.8M\n", "Payback beyond 2028 beyond 2028" ] }, @@ -7858,7 +8021,14 @@ "cell_type": "code", "execution_count": 24, "id": "6671014d", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.735125Z", + "iopub.status.busy": "2026-07-13T22:00:12.734908Z", + "iopub.status.idle": "2026-07-13T22:00:12.812825Z", + "shell.execute_reply": "2026-07-13T22:00:12.811222Z" + } + }, "outputs": [ { "data": { @@ -7870,7 +8040,7 @@ { "colorscale": [ [ - 0, + 0.0, "#cde2fb" ], [ @@ -7918,7 +8088,7 @@ "#104281" ], [ - 1, + 1.0, "#0d366b" ] ], @@ -7939,19 +8109,19 @@ "ygap": 2, "z": [ [ - 26532, - 66303, - 132606 + 26532.0, + 66303.0, + 132606.0 ], [ - 67688, - 169131, - 338167 + 67688.0, + 169131.0, + 338167.0 ], [ - 132606, - 331515, - 663030 + 132606.0, + 331515.0, + 663030.0 ] ] } @@ -8151,7 +8321,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -8187,7 +8357,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -8211,7 +8381,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -8247,7 +8417,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -8274,7 +8444,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -8310,7 +8480,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -8325,7 +8495,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -8361,7 +8531,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -8517,7 +8687,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -8553,7 +8723,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -8644,7 +8814,7 @@ ], "sequential": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -8680,13 +8850,13 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], "sequentialminus": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -8722,7 +8892,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ] @@ -8878,8 +9048,7 @@ "zerolinewidth": 1.5 } } - }, - "image/png": "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elmE5m04ce/WWM7B0ji0f5e6Nq2s3PkKa9CkRfcdhAASKoIlvNXOzWs0qO9rOn54r/1+ZaaDd3/tE5UoF7sW+typIzV5xJe68stFla0Spj5vfy3/5IF2LeShX7yl5RHT7P3M6MnWz/zL/uwcLI2jB3brxfahyp6nsD4fFcG2AV6DYAlvYNaanPLdv3X66D47ct5MB2/R6yPlLxXqeHmuwdKseTz4nfY6tneLoqIilTEktxp0eVMFy9TQycN7FP758zp9bJ/dr85RsIyaP/ehMoTkineWcBMsjZVzxmri1/9SaLNn1bTH+/d+I5AwJehgiT/PdUq4OxAs4Y3WrlioV7s31+w1RxSUIqU3vkTgb0ewhLfbuGqR3n++lcYvPqDAYLYNwO9BsIQ32bV+sQa+1UZ9p+1VQBDbAeDPIFg+pgiWwN/jxNGDmj9rsto985JdNgHAbyNYwtuZM30vnTvFnunbzKQB8NsIlvAmZnr2hkXTVLNVHyVhOwD8KQRLuA0jLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkAcEawhNsQLAEABsESAOCKYAkA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" + } }, "metadata": {}, "output_type": "display_data" @@ -8926,7 +9095,14 @@ "cell_type": "code", "execution_count": 25, "id": "faa1e95f", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.815150Z", + "iopub.status.busy": "2026-07-13T22:00:12.814916Z", + "iopub.status.idle": "2026-07-13T22:00:12.844312Z", + "shell.execute_reply": "2026-07-13T22:00:12.843515Z" + } + }, "outputs": [ { "name": "stdout", @@ -8964,21 +9140,21 @@ " \n", " \n", " low hours\n", - " 18,247,036\n", - " 17,952,036\n", - " 17,657,036\n", + " 16,647,036\n", + " 16,352,036\n", + " 16,057,036\n", " \n", " \n", " mid hours\n", - " 17,835,786\n", - " 17,423,286\n", - " 17,010,786\n", + " 16,235,786\n", + " 15,823,286\n", + " 15,410,786\n", " \n", " \n", " high hours\n", - " 17,424,536\n", - " 16,894,536\n", - " 16,364,536\n", + " 15,824,536\n", + " 15,294,536\n", + " 14,764,536\n", " \n", " \n", "\n", @@ -8986,9 +9162,9 @@ ], "text/plain": [ " $175/h $225/h $275/h\n", - "low hours 18,247,036 17,952,036 17,657,036\n", - "mid hours 17,835,786 17,423,286 17,010,786\n", - "high hours 17,424,536 16,894,536 16,364,536" + "low hours 16,647,036 16,352,036 16,057,036\n", + "mid hours 16,235,786 15,823,286 15,410,786\n", + "high hours 15,824,536 15,294,536 14,764,536" ] }, "metadata": {}, @@ -9044,14 +9220,21 @@ "cell_type": "code", "execution_count": 26, "id": "6516ea96", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.846063Z", + "iopub.status.busy": "2026-07-13T22:00:12.845859Z", + "iopub.status.idle": "2026-07-13T22:00:12.880547Z", + "shell.execute_reply": "2026-07-13T22:00:12.879217Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "All assertions passed.\n", - " benefits 3-yr $15.0M · tokens 3-yr $6.6M · corrected net 3-yr -$4.5M\n" + " benefits 3-yr $15.0M · tokens 3-yr $6.6M · corrected net 3-yr -$6.1M\n" ] } ], @@ -9079,6 +9262,9 @@ " MANAGED_SERVICES_ANNUAL * 2 / 12, tol=0.01) # Nov–Dec after go-live\n", "_approx(tco(\"ccaas_annual\"), 3_200_000) # signed contract overlay\n", "_approx(licence_costs_by_year(12, tco(\"ccaas_annual\"))[2027], 3_200_000)\n", + "# This notebook invoices the full contracted annual in year 1 (no ramp net-down):\n", + "for _y in YEARS:\n", + " _approx(licence_by_year[_y], LICENCE_ANNUAL)\n", "_contracts_at_default = (\n", " (current_state[\"annual_cost\"] - _seed_check[\"annual_cost\"]).abs().max() < 1\n", " and all(t == dt.date(2027, 12, 31) for t in current_state[\"contract_termination\"])\n", @@ -9200,7 +9386,14 @@ "cell_type": "code", "execution_count": 27, "id": "c4c025b5", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:12.882594Z", + "iopub.status.busy": "2026-07-13T22:00:12.882419Z", + "iopub.status.idle": "2026-07-13T22:00:12.931226Z", + "shell.execute_reply": "2026-07-13T22:00:12.930400Z" + } + }, "outputs": [ { "name": "stdout", @@ -9269,7 +9462,7 @@ "\n", "| | 2026 | 2027 | 2028 | 3-yr |\n", "|:----------------------------------------------------|----------:|----------:|----------:|----------:|\n", - "| CCaaS platform licences (contracted, ramp-adjusted) | 1,600,000 | 3,200,000 | 3,200,000 | 8,000,000 |\n", + "| CCaaS platform licences (contracted, ramp-adjusted) | 3,200,000 | 3,200,000 | 3,200,000 | 9,600,000 |\n", "| NTT PS + training (SOW billing milestones) | 1,179,723 | 1,012,723 | 0 | 2,192,446 |\n", "| NTT managed services (from MCX go-live) | 68,486 | 410,918 | 410,918 | 890,323 |\n", "| AI token consumption | 424,350 | 2,676,608 | 3,479,736 | 6,580,694 |\n", @@ -9288,11 +9481,11 @@ "| | As pitched (deck) | Corrected |\n", "|:-----------------------------|:--------------------|:------------|\n", "| 3-yr benefits | $15.0M | $15.0M |\n", - "| 3-yr incremental cost | $15.5M | $19.5M |\n", - "| 3-yr net | -$424K | -$4.5M |\n", - "| ROI (net ÷ incremental cost) | -3% | -23% |\n", - "| NPV @ 13.5% (deck rate) | -$1.5M | -$4.2M |\n", - "| NPV @ 8.0% (CTM treasury) | -$1.2M | -$4.3M |\n", + "| 3-yr incremental cost | $15.5M | $21.1M |\n", + "| 3-yr net | -$424K | -$6.1M |\n", + "| ROI (net ÷ incremental cost) | -3% | -29% |\n", + "| NPV @ 13.5% (deck rate) | -$1.5M | -$5.6M |\n", + "| NPV @ 8.0% (CTM treasury) | -$1.2M | -$5.8M |\n", "| Payback | beyond 2028 | beyond 2028 |\n", "\n", "#### Model state (JSON)\n", @@ -9305,7 +9498,7 @@ " \"2028\": 9672950\n", " },\n", " \"corrected_cost_by_year\": {\n", - " \"2026\": 4574668,\n", + " \"2026\": 6174668,\n", " \"2027\": 7696892,\n", " \"2028\": 7248154\n", " },\n", @@ -9315,16 +9508,16 @@ " \"2028\": 4300000\n", " },\n", " \"net_by_year_corrected\": {\n", - " \"2026\": -4574668,\n", + " \"2026\": -6174668,\n", " \"2027\": -2326842,\n", " \"2028\": 2424796\n", " },\n", " \"kpis_corrected\": {\n", " \"benefits_3yr\": 15043000,\n", - " \"incremental_cost_3yr\": 19519714,\n", - " \"net_3yr\": -4476714,\n", - " \"roi\": -0.2293,\n", - " \"npv\": -4178389,\n", + " \"incremental_cost_3yr\": 21119714,\n", + " \"net_3yr\": -6076714,\n", + " \"roi\": -0.2877,\n", + " \"npv\": -5588081,\n", " \"discount_rate\": 0.135,\n", " \"payback\": \"beyond 2028\"\n", " },\n", @@ -9500,7 +9693,7 @@ "widgets": { "application/vnd.jupyter.widget-state+json": { "state": { - "017a151c582947e3863296a36265e531": { + "062c84e8b0e24ee4a9b24c732665c7f8": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", @@ -9553,7 +9746,7 @@ "width": null } }, - "07dc99326a784494a3cd7debc40f00b5": { + "10b3118fbe3b46c89d22e101c9a280a8": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", @@ -9606,7 +9799,7 @@ "width": null } }, - "0c130b50aae44b58b1a908d97cd5bd5b": { + "1b74ac40a60341a9998d45d63a4275a4": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", @@ -9659,7 +9852,7 @@ "width": null } }, - "0ea9dd580548444480ebcdf1d670bd3d": { + "1e34f12588214862ad5402e3843bca43": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", @@ -9712,179 +9905,7 @@ "width": null } }, - "0fedd1577870444797ca09ff5585eda1": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "102e5a07ae634521b8b227533ec3efd6": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.date.DateInputWidget", - "_css": "\n .mljar-date-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-date-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-date-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n box-sizing: border-box;\n line-height: 1.4;\n }\n\n .mljar-date-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-date-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n @media (max-width: 768px) {\n .mljar-date-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-date-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-date-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"date\";\n input.classList.add(\"mljar-date-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Date\";\n input.value = model.get(\"value\") || \"\";\n\n const min = model.get(\"min\") || \"\";\n const max = model.get(\"max\") || \"\";\n if (min) input.min = min; else input.removeAttribute(\"min\");\n if (max) input.max = max; else input.removeAttribute(\"max\");\n\n input.disabled = !!model.get(\"disabled\");\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n model.save_changes();\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "NA — contract termination", - "layout": "IPY_MODEL_b13cb118cd464b7b8f3681b409c82645", - "layout_path": null, - "max": "", - "min": "", - "position": "inline", - "render_slot_id": null, - "source_cell_id": null, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": "2027-12-31" - } - }, - "1aa2430b53bf49f1a0447e0c8d912ef1": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.date.DateInputWidget", - "_css": "\n .mljar-date-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-date-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-date-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n box-sizing: border-box;\n line-height: 1.4;\n }\n\n .mljar-date-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-date-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n @media (max-width: 768px) {\n .mljar-date-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-date-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-date-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"date\";\n input.classList.add(\"mljar-date-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Date\";\n input.value = model.get(\"value\") || \"\";\n\n const min = model.get(\"min\") || \"\";\n const max = model.get(\"max\") || \"\";\n if (min) input.min = min; else input.removeAttribute(\"min\");\n if (max) input.max = max; else input.removeAttribute(\"max\");\n\n input.disabled = !!model.get(\"disabled\");\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n model.save_changes();\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "EMEA — contract termination", - "layout": "IPY_MODEL_92b7bca1e3924286b4d33f135e7e458f", - "layout_path": null, - "max": "", - "min": "", - "position": "inline", - "render_slot_id": null, - "source_cell_id": null, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": "2027-12-31" - } - }, - "25f437e26077490e8e6d4cacf5d9aef4": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "33904adcad3846a889f6fc54b7547d72": { + "1ebe071b962145cdbed25a1ae3dc8ccb": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -9903,11 +9924,98 @@ "cell_id": "", "disabled": false, "hidden": false, - "label": "Email auto-respond rate", - "layout": "IPY_MODEL_0c130b50aae44b58b1a908d97cd5bd5b", + "label": "ASIA — current platform cost ($/yr)", + "layout": "IPY_MODEL_4122ab35287242e2809394da2226977c", "layout_path": null, - "max": 0.6, - "min": 0, + "max": 8000000.0, + "min": 0.0, + "position": "inline", + "render_slot_id": null, + "source_cell_id": null, + "step": 10000.0, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 2069588.0 + } + }, + "1ebe6cf8ed324e68963a737c2f382822": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "26ad610c103f4511853bbdcfd637a108": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Auto-respond tokens per message 🟡", + "layout": "IPY_MODEL_5d76f9f81bdd44bfb6c72776727c26e9", + "layout_path": null, + "max": 0.5, + "min": 0.0, "position": "sidebar", "render_slot_id": null, "source_cell_id": null, @@ -9915,10 +10023,10 @@ "tabbable": null, "tooltip": null, "url_key": "", - "value": 0.255 + "value": 0.05 } }, - "3671a93bb2c84529a7df60afb5f7717f": { + "27e26a695a9d48c9bae29e3402ae1132": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -9938,39 +10046,54 @@ "disabled": false, "hidden": false, "label": "NA — current platform cost ($/yr)", - "layout": "IPY_MODEL_a81c32a4e2fe4dbea2cbe6fc8f931dc5", + "layout": "IPY_MODEL_65308a5920c44024a346f04a04539929", "layout_path": null, - "max": 8000000, - "min": 0, + "max": 8000000.0, + "min": 0.0, "position": "inline", "render_slot_id": null, "source_cell_id": null, - "step": 10000, + "step": 10000.0, "tabbable": null, "tooltip": null, "url_key": "", - "value": 3348969 + "value": 3348969.0 } }, - "3ca4dd3dd7e94b3d96da593e59135568": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", + "336a0118e33249788ad6521ecbba63d9": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "2.0.0", - "_model_name": "HTMLStyleModel", + "_anywidget_id": "mercury.date.DateInputWidget", + "_css": "\n .mljar-date-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-date-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-date-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n box-sizing: border-box;\n line-height: 1.4;\n }\n\n .mljar-date-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-date-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n @media (max-width: 768px) {\n .mljar-date-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-date-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-date-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"date\";\n input.classList.add(\"mljar-date-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Date\";\n input.value = model.get(\"value\") || \"\";\n\n const min = model.get(\"min\") || \"\";\n const max = model.get(\"max\") || \"\";\n if (min) input.min = min; else input.removeAttribute(\"min\");\n if (max) input.max = max; else input.removeAttribute(\"max\");\n\n input.disabled = !!model.get(\"disabled\");\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n model.save_changes();\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "StyleView", - "background": null, - "description_width": "", - "font_size": null, - "text_color": null + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "ASIA — contract termination", + "layout": "IPY_MODEL_3a09e832a71d4539bc6b6ea49bee0371", + "layout_path": null, + "max": "", + "min": "", + "position": "inline", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "2027-12-31" } }, - "4f247778c0c142c3b3e33fe3c305f99c": { + "345414b0120d421d8234208704d27582": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", @@ -10023,7 +10146,146 @@ "width": null } }, - "4f6b392701a84b0bab2fe540e6f4e7d0": { + "3946415fb4ac441fb7912a77a2f143d4": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Predictive Routing eligibility (%)", + "layout": "IPY_MODEL_89ecf935020b4804acd749e521c25259", + "layout_path": null, + "max": 100, + "min": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 100 + } + }, + "3a09e832a71d4539bc6b6ea49bee0371": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "4122ab35287242e2809394da2226977c": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "4c89a258ad0048e6a2797233bd2c04d2": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -10045,7 +10307,7 @@ "hidden": false, "label": "NA Email implements early (Jan 2027)", "last_changed_at": "", - "layout": "IPY_MODEL_bf8c77a2a21d4241a190c49f217aa324", + "layout": "IPY_MODEL_345414b0120d421d8234208704d27582", "layout_path": null, "n_toggles": 0, "position": "sidebar", @@ -10057,7 +10319,7 @@ "value": true } }, - "59f45f967ddd43488462821fd145a655": { + "4f18a5dd5d4245a9b7558564825d4a09": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -10076,715 +10338,22 @@ "cell_id": "", "disabled": false, "hidden": false, - "label": "ANZ — current platform cost ($/yr)", - "layout": "IPY_MODEL_8697c0d2b9444a0cbf8fbb6530eb07ef", + "label": "Genesys ramp — licence-free months", + "layout": "IPY_MODEL_e89c1e81df274bbfbacecb23781ef45b", "layout_path": null, - "max": 8000000, - "min": 0, + "max": 24.0, + "min": 0.0, "position": "inline", "render_slot_id": null, "source_cell_id": null, - "step": 10000, + "step": 1.0, "tabbable": null, "tooltip": null, "url_key": "", - "value": 677320 + "value": 6.0 } }, - "5eaafef4e78f4aa78714b5674c17aee0": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "6263f6cd732244a695f8a03352f62a73": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "680921ece5304830999d27ed3b568d10": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "70858dc708fb458a9d959c19f42f5797": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "7c917d16558d495e99f6d7c22e830786": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "2.0.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "2.0.0", - "_view_name": "HTMLView", - "cell_id": "", - "description": "", - "description_allow_html": false, - "layout": "IPY_MODEL_6263f6cd732244a695f8a03352f62a73", - "layout_path": null, - "placeholder": "​", - "position": "sidebar", - "render_slot_id": null, - "source_cell_id": null, - "style": "IPY_MODEL_3ca4dd3dd7e94b3d96da593e59135568", - "tabbable": null, - "tooltip": null, - "value": "" - } - }, - "7fdb7cf5a0aa476cbea97513d13f3218": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "8697c0d2b9444a0cbf8fbb6530eb07ef": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "8be1579c5e304bf0a7c1a211c5525c3a": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.number.NumberInputWidget", - "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "EMEA — current platform cost ($/yr)", - "layout": "IPY_MODEL_5eaafef4e78f4aa78714b5674c17aee0", - "layout_path": null, - "max": 8000000, - "min": 0, - "position": "inline", - "render_slot_id": null, - "source_cell_id": null, - "step": 10000, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": 1204124 - } - }, - "8d41dfe1b7244b3e8117abf9384baebd": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.number.NumberInputWidget", - "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "ASIA — current platform cost ($/yr)", - "layout": "IPY_MODEL_25f437e26077490e8e6d4cacf5d9aef4", - "layout_path": null, - "max": 8000000, - "min": 0, - "position": "inline", - "render_slot_id": null, - "source_cell_id": null, - "step": 10000, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": 2069588 - } - }, - "8effbc33f36444908062fbf8d6a02c28": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.number.NumberInputWidget", - "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "Auto-respond tokens per message 🟡", - "layout": "IPY_MODEL_9d250ae0110b4730bc22ead4d2ff898e", - "layout_path": null, - "max": 0.5, - "min": 0, - "position": "sidebar", - "render_slot_id": null, - "source_cell_id": null, - "step": 0.005, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": 0.05 - } - }, - "92b7bca1e3924286b4d33f135e7e458f": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "953d50cd99ce4cb9ac53b234e5715af4": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.date.DateInputWidget", - "_css": "\n .mljar-date-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-date-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-date-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n box-sizing: border-box;\n line-height: 1.4;\n }\n\n .mljar-date-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-date-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n @media (max-width: 768px) {\n .mljar-date-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-date-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-date-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"date\";\n input.classList.add(\"mljar-date-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Date\";\n input.value = model.get(\"value\") || \"\";\n\n const min = model.get(\"min\") || \"\";\n const max = model.get(\"max\") || \"\";\n if (min) input.min = min; else input.removeAttribute(\"min\");\n if (max) input.max = max; else input.removeAttribute(\"max\");\n\n input.disabled = !!model.get(\"disabled\");\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n model.save_changes();\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "ANZ — contract termination", - "layout": "IPY_MODEL_f0608ef0d6a74ac9aca6e4230926afbc", - "layout_path": null, - "max": "", - "min": "", - "position": "inline", - "render_slot_id": null, - "source_cell_id": null, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": "2027-12-31" - } - }, - "980b4421a67b435abb982f8a16742897": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "9d250ae0110b4730bc22ead4d2ff898e": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "a81c32a4e2fe4dbea2cbe6fc8f931dc5": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "a86270961a634af691f138beb4476834": { + "4f1b8f8777ef43deb835fe53c4dd2994": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -10804,21 +10373,21 @@ "disabled": false, "hidden": false, "label": "CCaaS licence run-rate ($/yr) — contracted", - "layout": "IPY_MODEL_07dc99326a784494a3cd7debc40f00b5", + "layout": "IPY_MODEL_619bb17b8bcc485bb479af80cbe2fd4c", "layout_path": null, - "max": 10000000, - "min": 0, + "max": 10000000.0, + "min": 0.0, "position": "inline", "render_slot_id": null, "source_cell_id": null, - "step": 100000, + "step": 100000.0, "tabbable": null, "tooltip": null, "url_key": "", - "value": 3200000 + "value": 3200000.0 } }, - "b13cb118cd464b7b8f3681b409c82645": { + "50400e98530e4b12ad374e31fe989863": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", @@ -10871,7 +10440,41 @@ "width": null } }, - "bf8c77a2a21d4241a190c49f217aa324": { + "5985ba7b869548d4a55b0490fb0fa302": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "toggle", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Copilot includes ASIA sites", + "last_changed_at": "", + "layout": "IPY_MODEL_5f3ae07d38ec488da4e4e00d05eed819", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "5d76f9f81bdd44bfb6c72776727c26e9": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", @@ -10924,7 +10527,845 @@ "width": null } }, - "c504335a40ff419fac8c15da3ab9c673": { + "5f3ae07d38ec488da4e4e00d05eed819": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "6190da45d1d444118fbd3272d96d09c4": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "AI Translate eligibility 🟡", + "layout": "IPY_MODEL_1ebe6cf8ed324e68963a737c2f382822", + "layout_path": null, + "max": 1.0, + "min": 0.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 0.01, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 0.01 + } + }, + "619bb17b8bcc485bb479af80cbe2fd4c": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "649ff563533144869b6a626a820a7d90": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "652b98f4c90c4007b1e4536218f9361a": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "65308a5920c44024a346f04a04539929": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "6ada443fa3844d198bc69221d8867bbc": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.date.DateInputWidget", + "_css": "\n .mljar-date-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-date-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-date-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n box-sizing: border-box;\n line-height: 1.4;\n }\n\n .mljar-date-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-date-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n @media (max-width: 768px) {\n .mljar-date-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-date-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-date-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"date\";\n input.classList.add(\"mljar-date-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Date\";\n input.value = model.get(\"value\") || \"\";\n\n const min = model.get(\"min\") || \"\";\n const max = model.get(\"max\") || \"\";\n if (min) input.min = min; else input.removeAttribute(\"min\");\n if (max) input.max = max; else input.removeAttribute(\"max\");\n\n input.disabled = !!model.get(\"disabled\");\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n model.save_changes();\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "NA — contract termination", + "layout": "IPY_MODEL_50400e98530e4b12ad374e31fe989863", + "layout_path": null, + "max": "", + "min": "", + "position": "inline", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "2027-12-31" + } + }, + "7013bd8d97d040cbb8172345f8a2829b": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "EMEA — current platform cost ($/yr)", + "layout": "IPY_MODEL_062c84e8b0e24ee4a9b24c732665c7f8", + "layout_path": null, + "max": 8000000.0, + "min": 0.0, + "position": "inline", + "render_slot_id": null, + "source_cell_id": null, + "step": 10000.0, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 1204124.0 + } + }, + "7971c319317c4e90bdfe69607c9e0de7": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.date.DateInputWidget", + "_css": "\n .mljar-date-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-date-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-date-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n box-sizing: border-box;\n line-height: 1.4;\n }\n\n .mljar-date-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-date-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n @media (max-width: 768px) {\n .mljar-date-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-date-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-date-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"date\";\n input.classList.add(\"mljar-date-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Date\";\n input.value = model.get(\"value\") || \"\";\n\n const min = model.get(\"min\") || \"\";\n const max = model.get(\"max\") || \"\";\n if (min) input.min = min; else input.removeAttribute(\"min\");\n if (max) input.max = max; else input.removeAttribute(\"max\");\n\n input.disabled = !!model.get(\"disabled\");\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n model.save_changes();\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "ANZ — contract termination", + "layout": "IPY_MODEL_1b74ac40a60341a9998d45d63a4275a4", + "layout_path": null, + "max": "", + "min": "", + "position": "inline", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "2027-12-31" + } + }, + "7a38470c3656494495096af0caafd68e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "7d6b41e9a308492588bab31ad47834e7": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n }\n\n .mljar-select-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: none;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n margin-top: 6px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n container.appendChild(dropdown);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target)) {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n isEditing = false;\n setOpen(false);\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n document.removeEventListener(\"click\", handleDocumentClick);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "13.5% (deck)", + "8.0% (CTM treasury)" + ], + "disabled": false, + "hidden": false, + "label": "NPV discount rate", + "layout": "IPY_MODEL_649ff563533144869b6a626a820a7d90", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "13.5% (deck)" + } + }, + "84926ebcbf1b4909870e0162052155da": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Email auto-respond rate", + "layout": "IPY_MODEL_90536af7df2044feaba9073e0e70d44f", + "layout_path": null, + "max": 0.6, + "min": 0.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 0.005, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 0.255 + } + }, + "89ecf935020b4804acd749e521c25259": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "90536af7df2044feaba9073e0e70d44f": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "bb1cf20444e2490597fd26df35490de9": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "ANZ — current platform cost ($/yr)", + "layout": "IPY_MODEL_dbdeb8e991de4af1bd01c0587db78993", + "layout_path": null, + "max": 8000000.0, + "min": 0.0, + "position": "inline", + "render_slot_id": null, + "source_cell_id": null, + "step": 10000.0, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 677320.0 + } + }, + "bd7adf2ad6a245559678679f2dafcd3e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "dbdeb8e991de4af1bd01c0587db78993": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e89c1e81df274bbfbacecb23781ef45b": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ed113f0cc8384a3d9c1acec6f8147c37": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f27fe4f9506d44b5948d86125bdf587b": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -10946,7 +11387,7 @@ "hidden": false, "label": "Include KB readiness (500–1,500 h)", "last_changed_at": "", - "layout": "IPY_MODEL_4f247778c0c142c3b3e33fe3c305f99c", + "layout": "IPY_MODEL_1e34f12588214862ad5402e3843bca43", "layout_path": null, "n_toggles": 0, "position": "sidebar", @@ -10958,127 +11399,7 @@ "value": true } }, - "c5225c1fa18141c994e18b0206c5d5da": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "cbe9d046880d47efa96880af499d66a5": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.slider.SliderWidget", - "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "Predictive Routing eligibility (%)", - "layout": "IPY_MODEL_980b4421a67b435abb982f8a16742897", - "layout_path": null, - "max": 100, - "min": 0, - "position": "sidebar", - "render_slot_id": null, - "source_cell_id": null, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": 100 - } - }, - "e05a62420de1441cb674d21455c9bcac": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.number.NumberInputWidget", - "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "AI Translate eligibility 🟡", - "layout": "IPY_MODEL_70858dc708fb458a9d959c19f42f5797", - "layout_path": null, - "max": 1, - "min": 0, - "position": "sidebar", - "render_slot_id": null, - "source_cell_id": null, - "step": 0.01, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": 0.01 - } - }, - "e074535aaefe479db9b3af810e3c0091": { + "f8456441f0ae4695ae97815b0b0aac84": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -11103,7 +11424,7 @@ "disabled": false, "hidden": false, "label": "Blended rate ($/h)", - "layout": "IPY_MODEL_0fedd1577870444797ca09ff5585eda1", + "layout": "IPY_MODEL_652b98f4c90c4007b1e4536218f9361a", "layout_path": null, "position": "sidebar", "render_slot_id": null, @@ -11114,163 +11435,35 @@ "value": "225" } }, - "e2dee7e397234208a377bd44d2046974": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.select.SelectWidget", - "_css": "\n .mljar-select-container {\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n }\n\n .mljar-select-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: none;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n margin-top: 6px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n container.appendChild(dropdown);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target)) {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n isEditing = false;\n setOpen(false);\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n document.removeEventListener(\"click\", handleDocumentClick);\n };\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "choices": [ - "13.5% (deck)", - "8.0% (CTM treasury)" - ], - "disabled": false, - "hidden": false, - "label": "NPV discount rate", - "layout": "IPY_MODEL_680921ece5304830999d27ed3b568d10", - "layout_path": null, - "position": "sidebar", - "render_slot_id": null, - "source_cell_id": null, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": "13.5% (deck)" - } - }, - "e631b576de444ebd85b131ce9bb235a6": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.checkbox.CheckboxWidget", - "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "appearance": "toggle", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "Copilot includes ASIA sites", - "last_changed_at": "", - "layout": "IPY_MODEL_0ea9dd580548444480ebcdf1d670bd3d", - "layout_path": null, - "n_toggles": 0, - "position": "sidebar", - "render_slot_id": null, - "source_cell_id": null, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": false - } - }, - "e86eb5e70e034abab1e1c23d3d21d00b": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.number.NumberInputWidget", - "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "disabled": false, - "hidden": false, - "label": "Genesys ramp — licence-free months", - "layout": "IPY_MODEL_017a151c582947e3863296a36265e531", - "layout_path": null, - "max": 24, - "min": 0, - "position": "inline", - "render_slot_id": null, - "source_cell_id": null, - "step": 1, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": 6 - } - }, - "f0608ef0d6a74ac9aca6e4230926afbc": { - "model_module": "@jupyter-widgets/base", + "fbc4f6246d0d4b36852ad6ad5f252d84": { + "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", - "model_name": "LayoutModel", + "model_name": "HTMLModel", "state": { - "_model_module": "@jupyter-widgets/base", + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", + "_model_name": "HTMLModel", "_view_count": null, - "_view_module": "@jupyter-widgets/base", + "_view_module": "@jupyter-widgets/controls", "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_10b3118fbe3b46c89d22e101c9a280a8", + "layout_path": null, + "placeholder": "​", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_bd7adf2ad6a245559678679f2dafcd3e", + "tabbable": null, + "tooltip": null, + "value": "" } }, - "f474fa6c1e744e09983ed11f7cde918a": { + "fd23a1e2c3f84fd4ba4803b26fdec9ff": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -11289,8 +11482,8 @@ "cell_id": "", "disabled": false, "hidden": false, - "label": "ASIA — contract termination", - "layout": "IPY_MODEL_c5225c1fa18141c994e18b0206c5d5da", + "label": "EMEA — contract termination", + "layout": "IPY_MODEL_7a38470c3656494495096af0caafd68e", "layout_path": null, "max": "", "min": "", @@ -11303,7 +11496,7 @@ "value": "2027-12-31" } }, - "f93ddd9cd9f941ad944210cc0245ae78": { + "ffa89c9fcbcd417896eaba9fec38d96c": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -11328,7 +11521,7 @@ "disabled": false, "hidden": false, "label": "Impl hours (V2 range)", - "layout": "IPY_MODEL_7fdb7cf5a0aa476cbea97513d13f3218", + "layout": "IPY_MODEL_ed113f0cc8384a3d9c1acec6f8147c37", "layout_path": null, "position": "sidebar", "render_slot_id": null, diff --git a/studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_virtual_agents.ipynb b/studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_virtual_agents.ipynb index 2956f91..bd761b7 100644 --- a/studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_virtual_agents.ipynb +++ b/studies/202607_CTM_GenesysCX/notebooks/ctm_business_case_virtual_agents.ipynb @@ -38,9 +38,16 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 1, "id": "9b5a64ed", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:37.300930Z", + "iopub.status.busy": "2026-07-13T22:00:37.300691Z", + "iopub.status.idle": "2026-07-13T22:00:37.792138Z", + "shell.execute_reply": "2026-07-13T22:00:37.791416Z" + } + }, "outputs": [ { "name": "stdout", @@ -142,9 +149,16 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 2, "id": "e1576add", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:37.794749Z", + "iopub.status.busy": "2026-07-13T22:00:37.793915Z", + "iopub.status.idle": "2026-07-13T22:00:37.825081Z", + "shell.execute_reply": "2026-07-13T22:00:37.824234Z" + } + }, "outputs": [ { "data": { @@ -261,30 +275,37 @@ "The honest phasing: Voice Bot goes live mid-2027 and ramps to mature by 2029; Agentic VA builds in\n", "2028, goes live partially in 2029, matures 2030. Implementation is a **separate line** (loads early,\n", "tapers to tuning). The platform-licence line carries only the **voice-attributable share** (default\n", - "= full contracted $3.2M/yr with a 6-month ramp in 2026) so this case isn't double-charged against\n", + "= full contracted $3.2M/yr, invoiced in full every year) so this case isn't double-charged against\n", "the feature-productivity notebook." ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 3, "id": "d6646cc1", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:37.826951Z", + "iopub.status.busy": "2026-07-13T22:00:37.826730Z", + "iopub.status.idle": "2026-07-13T22:00:37.840841Z", + "shell.execute_reply": "2026-07-13T22:00:37.839919Z" + } + }, "outputs": [ { "data": { "application/mercury+json": { - "model_id": "9537759ac3a24455a1ad5e12b6967c82", + "model_id": "9015105f420e40a6a4dac66945ef69ac", "position": "sidebar", "widget": "SelectWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "9537759ac3a24455a1ad5e12b6967c82", + "model_id": "9015105f420e40a6a4dac66945ef69ac", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -293,17 +314,17 @@ { "data": { "application/mercury+json": { - "model_id": "48a9b503a4b644df8578be36582850ad", + "model_id": "4bf597c64c4d4a479940c499a32f4ada", "position": "sidebar", "widget": "SelectWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "48a9b503a4b644df8578be36582850ad", + "model_id": "4bf597c64c4d4a479940c499a32f4ada", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -312,17 +333,17 @@ { "data": { "application/mercury+json": { - "model_id": "5f73500e219244b2ae119b6497e0ed1e", + "model_id": "d59e0ecb13204366bac47d02a7ec4f90", "position": "sidebar", "widget": "NumberInputWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "5f73500e219244b2ae119b6497e0ed1e", + "model_id": "d59e0ecb13204366bac47d02a7ec4f90", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -331,17 +352,17 @@ { "data": { "application/mercury+json": { - "model_id": "5210138abf164a0cb59db327b6e19b37", + "model_id": "edb7017bf89b4f77a4754df3bb3798de", "position": "sidebar", "widget": "CheckboxWidget" }, "application/vnd.jupyter.widget-view+json": { - "model_id": "5210138abf164a0cb59db327b6e19b37", + "model_id": "edb7017bf89b4f77a4754df3bb3798de", "version_major": 2, "version_minor": 1 }, "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -361,9 +382,16 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 4, "id": "f19d7263", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:37.842801Z", + "iopub.status.busy": "2026-07-13T22:00:37.842598Z", + "iopub.status.idle": "2026-07-13T22:00:37.853784Z", + "shell.execute_reply": "2026-07-13T22:00:37.852999Z" + } + }, "outputs": [ { "data": { @@ -428,7 +456,7 @@ " \n", " \n", " Platform licence ($)\n", - " 1,600,000\n", + " 3,200,000\n", " 3,200,000\n", " 3,200,000\n", " 3,200,000\n", @@ -444,7 +472,7 @@ "Agentic VA benefit ramp 0 0 0 0 1\n", "VB implementation ($) 150,000 450,000 150,000 150,000 150,000\n", "VA implementation ($) 0 0 400,000 150,000 150,000\n", - "Platform licence ($) 1,600,000 3,200,000 3,200,000 3,200,000 3,200,000" + "Platform licence ($) 3,200,000 3,200,000 3,200,000 3,200,000 3,200,000" ] }, "metadata": {}, @@ -467,8 +495,9 @@ "# Implementation (separate, $) — loads early, tapers to tuning.\n", "VB_IMPL = {2026: 150_000, 2027: 450_000, 2028: 150_000, 2029: 150_000, 2030: 150_000}\n", "VA_IMPL = {2026: 0, 2027: 0, 2028: 400_000, 2029: 150_000, 2030: 150_000}\n", - "# Platform licence: 6-month ramp in 2026, full thereafter.\n", - "LICENCE = {2026: LICENCE_ANNUAL * 0.5, **{y: LICENCE_ANNUAL for y in YEARS[1:]}}\n", + "# Platform licence: INVOICED in full every year ($3.2M) — the order-form\n", + "# ramp gives free months operationally but CTM's invoice is not netted down.\n", + "LICENCE = {y: LICENCE_ANNUAL for y in YEARS}\n", "\n", "phasing = pd.DataFrame({\n", " \"Voice Bot benefit ramp\": VB_RAMP,\n", @@ -482,15 +511,22 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 5, "id": "2dcc82f5", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:37.856097Z", + "iopub.status.busy": "2026-07-13T22:00:37.855681Z", + "iopub.status.idle": "2026-07-13T22:00:37.867461Z", + "shell.execute_reply": "2026-07-13T22:00:37.866473Z" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "headline realistic: 5-yr net $21.8M, NPV@8.0% $15.4M\n" + "headline realistic: 5-yr net $20.2M, NPV@8.0% $13.9M\n" ] } ], @@ -565,9 +601,16 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 6, "id": "9ae520ec", - "metadata": {}, + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-13T22:00:37.869931Z", + "iopub.status.busy": "2026-07-13T22:00:37.869476Z", + "iopub.status.idle": "2026-07-13T22:00:39.300880Z", + "shell.execute_reply": "2026-07-13T22:00:39.298541Z" + } + }, "outputs": [ { "data": { @@ -595,7 +638,7 @@ "2030" ], "y": [ - 0, + 0.0, 3490539.888701922, 9075403.710624997, 13962159.554807687, @@ -621,9 +664,9 @@ "2030" ], "y": [ - 0, - 0, - 0, + 0.0, + 0.0, + 0.0, 1555783.49325, 3889458.733125 ] @@ -647,11 +690,11 @@ "2030" ], "y": [ - -1600000, - -3200000, - -3200000, - -3200000, - -3200000 + -3200000.0, + -3200000.0, + -3200000.0, + -3200000.0, + -3200000.0 ] }, { @@ -699,11 +742,11 @@ "2030" ], "y": [ - 0, - -243060, - -631956, - -972240, - -972240 + -0.0, + -243060.0, + -631956.0, + -972240.0, + -972240.0 ] }, { @@ -725,11 +768,11 @@ "2030" ], "y": [ - 0, - 0, - 0, + -0.0, + -0.0, + -0.0, -1473278.4000000001, - -3683196 + -3683196.0 ] }, { @@ -756,7 +799,7 @@ "2030" ], "y": { - "bdata": "AAAAAPCzOsHzAz8OJGxAwZW+tsy/YkNBHpPqB7kaZ0HdqJDol8x0QQ==", + "bdata": "AAAAAPiOScHzAz8OJKFMwVT62jL/tixBHpPqB3kNZEHdqJDo90VzQQ==", "dtype": "f8" } } @@ -769,9 +812,9 @@ "size": 12 }, "showarrow": false, - "text": "-$1.8M", + "text": "-$3.4M", "x": 0, - "y": -1750000, + "y": -3350000.0, "yshift": -16 }, { @@ -780,9 +823,9 @@ "size": 12 }, "showarrow": false, - "text": "-$2.2M", + "text": "-$3.8M", "x": 1, - "y": -2152520.111298078, + "y": -3752520.111298078, "yshift": -16 }, { @@ -791,9 +834,9 @@ "size": 12 }, "showarrow": false, - "text": "$2.5M", + "text": "$941K", "x": 2, - "y": 2540927.5993269184, + "y": 940927.5993269184, "yshift": 16 }, { @@ -802,9 +845,9 @@ "size": 12 }, "showarrow": false, - "text": "$12.1M", + "text": "$10.5M", "x": 3, - "y": 12113352.247384604, + "y": 10513352.247384604, "yshift": 16 }, { @@ -813,9 +856,9 @@ "size": 12 }, "showarrow": false, - "text": "$21.8M", + "text": "$20.2M", "x": 4, - "y": 21809534.53531729, + "y": 20209534.53531729, "yshift": 16 } ], @@ -922,7 +965,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -958,7 +1001,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -982,7 +1025,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -1018,7 +1061,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -1045,7 +1088,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -1081,7 +1124,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -1096,7 +1139,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -1132,7 +1175,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -1288,7 +1331,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -1324,7 +1367,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -1415,7 +1458,7 @@ ], "sequential": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -1451,13 +1494,13 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], "sequentialminus": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -1493,7 +1536,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ] @@ -1627,7 +1670,7 @@ "color": "#0b0b0b", "size": 16 }, - "text": "Virtual agents — 5-year case (Realistic)
Benefits (up) vs cost lines (down) · 5-yr net $21.8M · NPV@8.0% $15.4M · payback Jun 2028", + "text": "Virtual agents — 5-year case (Realistic)
Benefits (up) vs cost lines (down) · 5-yr net $20.2M · NPV@8.0% $13.9M · payback Oct 2028", "x": 0.02, "xanchor": "left" }, @@ -1697,10 +1740,10 @@ "id": "8be664ad", "metadata": { "execution": { - "iopub.execute_input": "2026-07-13T19:59:14.988775Z", - "iopub.status.busy": "2026-07-13T19:59:14.988546Z", - "iopub.status.idle": "2026-07-13T19:59:15.014307Z", - "shell.execute_reply": "2026-07-13T19:59:15.013730Z" + "iopub.execute_input": "2026-07-13T22:00:39.303401Z", + "iopub.status.busy": "2026-07-13T22:00:39.303115Z", + "iopub.status.idle": "2026-07-13T22:00:39.340669Z", + "shell.execute_reply": "2026-07-13T22:00:39.339767Z" } }, "outputs": [ @@ -1812,12 +1855,12 @@ " \n", " \n", " Platform licence (voice-attributable)\n", - " 1,600,000\n", " 3,200,000\n", " 3,200,000\n", " 3,200,000\n", " 3,200,000\n", - " 14,400,000\n", + " 3,200,000\n", + " 16,000,000\n", " \n", " \n", " Implementation\n", @@ -1848,12 +1891,12 @@ " \n", " \n", " TOTAL cost\n", - " 1,750,000\n", + " 3,350,000\n", " 3,893,060\n", " 4,381,956\n", " 5,945,518\n", " 8,155,436\n", - " 24,125,970\n", + " 25,725,970\n", " \n", " \n", "\n", @@ -1861,18 +1904,18 @@ ], "text/plain": [ " 2026 2027 2028 2029 \\\n", - "Platform licence (voice-attributable) 1,600,000 3,200,000 3,200,000 3,200,000 \n", + "Platform licence (voice-attributable) 3,200,000 3,200,000 3,200,000 3,200,000 \n", "Implementation 150,000 450,000 550,000 300,000 \n", "Voice Bot tokens 0 243,060 631,956 972,240 \n", "Agentic VA tokens 0 0 0 1,473,278 \n", - "TOTAL cost 1,750,000 3,893,060 4,381,956 5,945,518 \n", + "TOTAL cost 3,350,000 3,893,060 4,381,956 5,945,518 \n", "\n", " 2030 5-yr \n", - "Platform licence (voice-attributable) 3,200,000 14,400,000 \n", + "Platform licence (voice-attributable) 3,200,000 16,000,000 \n", "Implementation 300,000 1,750,000 \n", "Voice Bot tokens 972,240 2,819,496 \n", "Agentic VA tokens 3,683,196 5,156,474 \n", - "TOTAL cost 8,155,436 24,125,970 " + "TOTAL cost 8,155,436 25,725,970 " ] }, "metadata": {}, @@ -1921,7 +1964,7 @@ " \n", " \n", " cost\n", - " 1,750,000\n", + " 3,350,000\n", " 3,893,060\n", " 4,381,956\n", " 5,945,518\n", @@ -1931,13 +1974,13 @@ " \n", " \n", " net\n", - " -1,750,000\n", + " -3,350,000\n", " -402,520\n", " 4,693,448\n", " 9,572,425\n", " 9,696,182\n", " 0\n", - " 21,809,535\n", + " 20,209,535\n", " \n", " \n", "\n", @@ -1946,13 +1989,13 @@ "text/plain": [ " 2026 2027 2028 2029 2030 cumulative net \\\n", "benefit 0 3,490,540 9,075,404 15,517,943 17,851,618 0 \n", - "cost 1,750,000 3,893,060 4,381,956 5,945,518 8,155,436 0 \n", - "net -1,750,000 -402,520 4,693,448 9,572,425 9,696,182 0 \n", + "cost 3,350,000 3,893,060 4,381,956 5,945,518 8,155,436 0 \n", + "net -3,350,000 -402,520 4,693,448 9,572,425 9,696,182 0 \n", "\n", " 5-yr \n", "benefit NaN \n", "cost NaN \n", - "net 21,809,535 " + "net 20,209,535 " ] }, "metadata": {}, @@ -1996,10 +2039,10 @@ "id": "9d172a1d", "metadata": { "execution": { - "iopub.execute_input": "2026-07-13T19:59:15.016591Z", - "iopub.status.busy": "2026-07-13T19:59:15.016396Z", - "iopub.status.idle": "2026-07-13T19:59:15.052357Z", - "shell.execute_reply": "2026-07-13T19:59:15.051192Z" + "iopub.execute_input": "2026-07-13T22:00:39.344639Z", + "iopub.status.busy": "2026-07-13T22:00:39.344007Z", + "iopub.status.idle": "2026-07-13T22:00:39.388628Z", + "shell.execute_reply": "2026-07-13T22:00:39.385046Z" } }, "outputs": [ @@ -2034,7 +2077,7 @@ "2030" ], "y": { - "bdata": "AAAAAPCzOsEcuZHjDLBKwf0zppm5kUHBvi85PXoPPEEU9lagLQJXQQ==", + "bdata": "AAAAAPiOScGO3MhxhnJTwf0zppm5xk3B8H3J6dErDUEU9lagredQQQ==", "dtype": "f8" } }, @@ -2062,7 +2105,7 @@ "2030" ], "y": { - "bdata": "AAAAAPCzOsHzAz8OJGxAwZW+tsy/YkNBHpPqB7kaZ0HdqJDol8x0QQ==", + "bdata": "AAAAAPiOScHzAz8OJKFMwVT62jL/tixBHpPqB3kNZEHdqJDo90VzQQ==", "dtype": "f8" } } @@ -2075,10 +2118,10 @@ "size": 12 }, "showarrow": false, - "text": "$6.0M", + "text": "$4.4M", "x": 4, "xshift": 6, - "y": 6031542.505307693 + "y": 4431542.505307693 }, { "font": { @@ -2086,10 +2129,10 @@ "size": 12 }, "showarrow": false, - "text": "$21.8M", + "text": "$20.2M", "x": 4, "xshift": 6, - "y": 21809534.53531729 + "y": 20209534.53531729 } ], "bargap": 0.42, @@ -2194,7 +2237,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2230,7 +2273,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2254,7 +2297,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2290,7 +2333,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2317,7 +2360,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2353,7 +2396,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2368,7 +2411,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2404,7 +2447,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2560,7 +2603,7 @@ }, "colorscale": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2596,7 +2639,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], @@ -2687,7 +2730,7 @@ ], "sequential": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2723,13 +2766,13 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ], "sequentialminus": [ [ - 0, + 0.0, "#0d0887" ], [ @@ -2765,7 +2808,7 @@ "#fdca26" ], [ - 1, + 1.0, "#f0f921" ] ] @@ -2960,28 +3003,28 @@ " \n", " \n", " 5-yr cost\n", - " $19.3M\n", - " $24.1M\n", + " $20.9M\n", + " $25.7M\n", " \n", " \n", " 5-yr net\n", - " $6.0M\n", - " $21.8M\n", + " $4.4M\n", + " $20.2M\n", " \n", " \n", " NPV @ 8.0%\n", - " $3.7M\n", - " $15.4M\n", + " $2.2M\n", + " $13.9M\n", " \n", " \n", " NPV @ 13.5%\n", - " $2.6M\n", - " $12.3M\n", + " $1.2M\n", + " $10.9M\n", " \n", " \n", " payback\n", - " Jul 2029\n", - " Jun 2028\n", + " Dec 2029\n", + " Oct 2028\n", " \n", " \n", "\n", @@ -2990,11 +3033,11 @@ "text/plain": [ " Floor Realistic\n", "5-yr benefits $25.4M $45.9M\n", - "5-yr cost $19.3M $24.1M\n", - "5-yr net $6.0M $21.8M\n", - "NPV @ 8.0% $3.7M $15.4M\n", - "NPV @ 13.5% $2.6M $12.3M\n", - "payback Jul 2029 Jun 2028" + "5-yr cost $20.9M $25.7M\n", + "5-yr net $4.4M $20.2M\n", + "NPV @ 8.0% $2.2M $13.9M\n", + "NPV @ 13.5% $1.2M $10.9M\n", + "payback Dec 2029 Oct 2028" ] }, "metadata": {}, @@ -3040,10 +3083,10 @@ "id": "6e07d6ac", "metadata": { "execution": { - "iopub.execute_input": "2026-07-13T19:59:15.054864Z", - "iopub.status.busy": "2026-07-13T19:59:15.054679Z", - "iopub.status.idle": "2026-07-13T19:59:15.066082Z", - "shell.execute_reply": "2026-07-13T19:59:15.065079Z" + "iopub.execute_input": "2026-07-13T22:00:39.392305Z", + "iopub.status.busy": "2026-07-13T22:00:39.392004Z", + "iopub.status.idle": "2026-07-13T22:00:39.407960Z", + "shell.execute_reply": "2026-07-13T22:00:39.406704Z" } }, "outputs": [ @@ -3089,16 +3132,16 @@ " $23.1M\n", " $1.1M\n", " 21.5:1\n", - " $6.6M\n", - " Jun 2029\n", + " $5.0M\n", + " Oct 2029\n", " \n", " \n", " Realistic\n", " $40.5M\n", " $2.8M\n", " 14.4:1\n", - " $22.2M\n", - " Jun 2028\n", + " $20.6M\n", + " Sep 2028\n", " \n", " \n", "\n", @@ -3107,13 +3150,13 @@ "text/plain": [ " VB 5-yr benefit VB 5-yr tokens benefit : token VB-only 5-yr net \\\n", "scenario \n", - "Floor $23.1M $1.1M 21.5:1 $6.6M \n", - "Realistic $40.5M $2.8M 14.4:1 $22.2M \n", + "Floor $23.1M $1.1M 21.5:1 $5.0M \n", + "Realistic $40.5M $2.8M 14.4:1 $20.6M \n", "\n", " payback \n", "scenario \n", - "Floor Jun 2029 \n", - "Realistic Jun 2028 " + "Floor Oct 2029 \n", + "Realistic Sep 2028 " ] }, "metadata": {}, @@ -3123,7 +3166,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "VB-only realistic 5-yr net $22.2M\n" + "VB-only realistic 5-yr net $20.6M\n" ] } ], @@ -3186,10 +3229,10 @@ "id": "5c6bff66", "metadata": { "execution": { - "iopub.execute_input": "2026-07-13T19:59:15.068865Z", - "iopub.status.busy": "2026-07-13T19:59:15.068685Z", - "iopub.status.idle": "2026-07-13T19:59:15.201240Z", - "shell.execute_reply": "2026-07-13T19:59:15.200251Z" + "iopub.execute_input": "2026-07-13T22:00:39.410739Z", + "iopub.status.busy": "2026-07-13T22:00:39.410552Z", + "iopub.status.idle": "2026-07-13T22:00:39.582282Z", + "shell.execute_reply": "2026-07-13T22:00:39.581441Z" } }, "outputs": [ @@ -3215,7 +3258,7 @@ "| Agentic VA benefit ramp | 0 | 0 | 0 | 0 | 1 |\n", "| VB implementation ($) | 150,000 | 450,000 | 150,000 | 150,000 | 150,000 |\n", "| VA implementation ($) | 0 | 0 | 400,000 | 150,000 | 150,000 |\n", - "| Platform licence ($) | 1,600,000 | 3,200,000 | 3,200,000 | 3,200,000 | 3,200,000 |\n", + "| Platform licence ($) | 3,200,000 | 3,200,000 | 3,200,000 | 3,200,000 | 3,200,000 |\n", "\n", "#### Floor — benefit by line × year\n", "\n", @@ -3228,7 +3271,7 @@ "\n", "| | 2026 | 2027 | 2028 | 2029 | 2030 |\n", "|:--------------------------------------|----------:|----------:|----------:|----------:|----------:|\n", - "| Platform licence (voice-attributable) | 1,600,000 | 3,200,000 | 3,200,000 | 3,200,000 | 3,200,000 |\n", + "| Platform licence (voice-attributable) | 3,200,000 | 3,200,000 | 3,200,000 | 3,200,000 | 3,200,000 |\n", "| Implementation | 150,000 | 450,000 | 550,000 | 300,000 | 300,000 |\n", "| Voice Bot tokens | 0 | 92,604 | 240,770 | 370,416 | 370,416 |\n", "| Agentic VA tokens | 0 | 0 | 0 | 604,426 | 1,511,064 |\n", @@ -3244,7 +3287,7 @@ "\n", "| | 2026 | 2027 | 2028 | 2029 | 2030 |\n", "|:--------------------------------------|----------:|----------:|----------:|----------:|----------:|\n", - "| Platform licence (voice-attributable) | 1,600,000 | 3,200,000 | 3,200,000 | 3,200,000 | 3,200,000 |\n", + "| Platform licence (voice-attributable) | 3,200,000 | 3,200,000 | 3,200,000 | 3,200,000 | 3,200,000 |\n", "| Implementation | 150,000 | 450,000 | 550,000 | 300,000 | 300,000 |\n", "| Voice Bot tokens | 0 | 243,060 | 631,956 | 972,240 | 972,240 |\n", "| Agentic VA tokens | 0 | 0 | 0 | 1,473,278 | 3,683,196 |\n", @@ -3290,24 +3333,24 @@ " \"2030\": 9574052\n", " },\n", " \"cost_by_year\": {\n", - " \"2026\": 1750000,\n", + " \"2026\": 3350000,\n", " \"2027\": 3742604,\n", " \"2028\": 3990770,\n", " \"2029\": 4474842,\n", " \"2030\": 5381480\n", " },\n", " \"net_by_year\": {\n", - " \"2026\": -1750000,\n", + " \"2026\": -3350000,\n", " \"2027\": -1748010,\n", " \"2028\": 1195175,\n", " \"2029\": 4141805,\n", " \"2030\": 4192572\n", " },\n", - " \"net_5yr\": 6031543,\n", - " \"npv_primary\": 3727506,\n", - " \"npv_sensitivity\": 2640311,\n", - " \"payback\": \"Jul 2029\",\n", - " \"vb_only_net_5yr\": 6613087\n", + " \"net_5yr\": 4431543,\n", + " \"npv_primary\": 2246024,\n", + " \"npv_sensitivity\": 1230619,\n", + " \"payback\": \"Dec 2029\",\n", + " \"vb_only_net_5yr\": 5013087\n", " },\n", " \"realistic\": {\n", " \"benefit_by_year\": {\n", @@ -3318,24 +3361,24 @@ " \"2030\": 17851618\n", " },\n", " \"cost_by_year\": {\n", - " \"2026\": 1750000,\n", + " \"2026\": 3350000,\n", " \"2027\": 3893060,\n", " \"2028\": 4381956,\n", " \"2029\": 5945518,\n", " \"2030\": 8155436\n", " },\n", " \"net_by_year\": {\n", - " \"2026\": -1750000,\n", + " \"2026\": -3350000,\n", " \"2027\": -402520,\n", " \"2028\": 4693448,\n", " \"2029\": 9572425,\n", " \"2030\": 9696182\n", " },\n", - " \"net_5yr\": 21809535,\n", - " \"npv_primary\": 15395420,\n", - " \"npv_sensitivity\": 12271658,\n", - " \"payback\": \"Jun 2028\",\n", - " \"vb_only_net_5yr\": 22220767\n", + " \"net_5yr\": 20209535,\n", + " \"npv_primary\": 13913939,\n", + " \"npv_sensitivity\": 10861966,\n", + " \"payback\": \"Oct 2028\",\n", + " \"vb_only_net_5yr\": 20620767\n", " }\n", " }\n", "}\n", @@ -3407,42 +3450,7 @@ "widgets": { "application/vnd.jupyter.widget-state+json": { "state": { - "1eb499ff637b460186eb8485dc2c79cd": { - "model_module": "anywidget", - "model_module_version": "~0.11.*", - "model_name": "AnyModel", - "state": { - "_anywidget_id": "mercury.select.SelectWidget", - "_css": "\n .mljar-select-container {\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n }\n\n .mljar-select-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: none;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n margin-top: 6px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", - "_dom_classes": [], - "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n container.appendChild(dropdown);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target)) {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n isEditing = false;\n setOpen(false);\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n document.removeEventListener(\"click\", handleDocumentClick);\n };\n }\n export default { render };\n ", - "_model_module": "anywidget", - "_model_module_version": "~0.11.*", - "_model_name": "AnyModel", - "_view_count": null, - "_view_module": "anywidget", - "_view_module_version": "~0.11.*", - "_view_name": "AnyView", - "cell_id": "", - "choices": [ - "floor", - "realistic" - ], - "disabled": false, - "hidden": false, - "label": "Headline scenario", - "layout": "IPY_MODEL_bf42f2d19c434de4926d58c3e7b48d2e", - "layout_path": null, - "position": "sidebar", - "render_slot_id": null, - "source_cell_id": null, - "tabbable": null, - "tooltip": null, - "url_key": "", - "value": "realistic" - } - }, - "2a96c544ee55490aa9e41d9c3cae7788": { + "00d64fd0d74244de90fd31e6aa312a88": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", @@ -3495,7 +3503,60 @@ "width": null } }, - "3b8e09a0b1eb47c29cb03829fcf7363a": { + "288ac9b4291a431a8b34bd9c8a8f4077": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "4bf597c64c4d4a479940c499a32f4ada": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -3519,7 +3580,7 @@ "disabled": false, "hidden": false, "label": "NPV discount rate (primary)", - "layout": "IPY_MODEL_df9473c074854514aa16850d83174b0a", + "layout": "IPY_MODEL_00d64fd0d74244de90fd31e6aa312a88", "layout_path": null, "position": "sidebar", "render_slot_id": null, @@ -3530,7 +3591,7 @@ "value": "8.0% (CTM treasury)" } }, - "714e29afc099414f81adfbc789ddd589": { + "51e7784eabda4371a1fa5fb59cbc9065": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", @@ -3583,7 +3644,42 @@ "width": null } }, - "7d3e63e84499491ba71b4a2d3074036b": { + "9015105f420e40a6a4dac66945ef69ac": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n margin-bottom: 8px;\n padding-left: 4px;\n padding-right: 4px;\n }\n\n .mljar-select-label {\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n border-width: 2px;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: none;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n margin-top: 6px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n container.appendChild(dropdown);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target)) {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n isEditing = false;\n setOpen(false);\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n document.removeEventListener(\"click\", handleDocumentClick);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "floor", + "realistic" + ], + "disabled": false, + "hidden": false, + "label": "Headline scenario", + "layout": "IPY_MODEL_dcc9a46d44bd483e9026797f7fe35a20", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "realistic" + } + }, + "d59e0ecb13204366bac47d02a7ec4f90": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -3603,21 +3699,74 @@ "disabled": false, "hidden": false, "label": "Voice-attributable platform licence ($/yr)", - "layout": "IPY_MODEL_2a96c544ee55490aa9e41d9c3cae7788", + "layout": "IPY_MODEL_288ac9b4291a431a8b34bd9c8a8f4077", "layout_path": null, - "max": 6000000, - "min": 0, + "max": 6000000.0, + "min": 0.0, "position": "sidebar", "render_slot_id": null, "source_cell_id": null, - "step": 100000, + "step": 100000.0, "tabbable": null, "tooltip": null, "url_key": "", - "value": 3200000 + "value": 3200000.0 } }, - "8c09da957880482e807df2152f65db4c": { + "dcc9a46d44bd483e9026797f7fe35a20": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "edb7017bf89b4f77a4754df3bb3798de": { "model_module": "anywidget", "model_module_version": "~0.11.*", "model_name": "AnyModel", @@ -3639,7 +3788,7 @@ "hidden": false, "label": "Include Agentic VA layer", "last_changed_at": "", - "layout": "IPY_MODEL_714e29afc099414f81adfbc789ddd589", + "layout": "IPY_MODEL_51e7784eabda4371a1fa5fb59cbc9065", "layout_path": null, "n_toggles": 0, "position": "sidebar", @@ -3650,112 +3799,6 @@ "url_key": "", "value": true } - }, - "bf42f2d19c434de4926d58c3e7b48d2e": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "df9473c074854514aa16850d83174b0a": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "2.0.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "2.0.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border_bottom": null, - "border_left": null, - "border_right": null, - "border_top": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } } }, "version_major": 2, diff --git a/studies/202607_CX_AI_Diagnostic/README.md b/studies/202607_CX_AI_Diagnostic/README.md new file mode 100644 index 0000000..f3422d4 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/README.md @@ -0,0 +1,74 @@ +# CX AI Advisory Diagnostic + +Facilitator's cockpit for the CX AI Advisory diagnostic workshop +(Mercury Notebook Pattern — see +[`docs/Mercury_Notebook_Pattern_V1-00.md`](../../docs/Mercury_Notebook_Pattern_V1-00.md)). +Captures capability scores across **12 competencies** in four dimensions +(Strategy & Value, Foundations, Delivery, Sustain), ingests the client's +operational baseline, computes **value-at-stake bounded by capability +gaps**, and exports a structured engagement record. + +Single facilitator, live half-day workshop, 4–8 client participants. +Not for client self-service, unattended use, or deployment. +Specification: [`docs/build_spec_v1.md`](docs/build_spec_v1.md). + +## Run + +```bash +python -m venv .venv && .venv/bin/pip install -e ".[dev]" # once +source .venv/bin/activate + +mercury --working-dir . # the workshop stage (serve from study root) +jupyter lab # analyst view (backstage) +pytest # engine pins +python scripts/export_report.py # exports/diagnostic.{html,md} +``` + +The notebook is **generated** — edit cell sources in +`scripts/build_notebook.py`, then: + +```bash +python scripts/build_notebook.py +jupyter nbconvert --to notebook --execute --inplace notebooks/diagnostic.ipynb +``` + +## Layout + +``` +diaglib/ # THE study package — all math and contracts +│ models.py # pydantic models: engagement data + config schema +│ config.py # configs/*.yaml loading, base+overlay merge +│ scoring.py # score aggregation, participants, assembly +│ value_math.py # drivers, capping, trapped value, unlock sequence +│ visuals.py # plotly builders (house chrome) +│ export.py # exports/{engagement_id}.json + .csv +│ staging.py # stage/backstage detection (pattern verbatim) +configs/ +│ base.yaml # the instrument: 12 competencies, capping heuristic +│ contact_center.yaml # value drivers + unlock costs (🟡 ranges) +│ financial_services.yaml # stub — scoring only until drivers added +notebooks/diagnostic.ipynb # the deliverable (generated) +scripts/ # build_notebook.py · export_report.py +tests/ # hand-checked pins for every engine number +exports/ # per-engagement JSON/CSV + report sources (gitignored) +``` + +## Design decisions (deviations from the build spec, both additive) + +- **Unlock moves are tier lifts of the binding set** (`competency_ids` + plural). When several foundations tie at the weakest level, lifting one + alone honestly unlocks nothing — the set is the move, costs summed, + weeks = longest parallel workstream. +- **"One screen per competency" is a `Now scoring` selector**, not a + Next button — Mercury's reactivity model makes stateless buttons + awkward, and the selector adds random access for revisits. All score + sliders stay live in the sidebar. +- `requirements.txt` is replaced by `pyproject.toml` per the pattern + (`pip install -e .` provisions everything). + +## Before using with a real client + +The value-driver ranges and unlock costs in `contact_center.yaml` are +🟡 placeholders (build spec §12): back them with cited public sources or +"based on N engagements" framing, and tune `cost_per_replacement_default` +per engagement. diff --git a/studies/202607_CX_AI_Diagnostic/config.toml b/studies/202607_CX_AI_Diagnostic/config.toml new file mode 100644 index 0000000..d073506 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/config.toml @@ -0,0 +1,73 @@ +# Mercury app-shell theme — NTT DATA brand (light), modern surfaces. +# See docs/brand.md for the source palette. Loaded from the directory where +# you launch `mercury` (this study root); restart the server to apply. + +[main] +title = "CX AI Advisory Diagnostic" +favicon_emoji = "🧪" +footer = "CX AI Advisory Diagnostic" +notebooks_button_label = "Diagnostics" + +[welcome] +header = "CX AI Advisory Diagnostic" +message = """ +The facilitator's cockpit for the CX AI Advisory diagnostic workshop. +Capture the engagement, the operational baseline, and capability scores +across 12 competencies in the sidebar; the value-at-stake analysis and +visuals recompute live on the page. Click **Export JSON + CSV** at the +bottom of the page to write the structured engagement record to +`exports/`. Report sources: `python scripts/export_report.py`. +""" + +[theme] +# ── Type — Georgia headings, Arial body (web-safe; no network fetch). ── +font_family = "Arial, 'Helvetica Neue', Helvetica, sans-serif" +heading_font_family = "Georgia, 'Times New Roman', Times, serif" +font_size = "15px" +font_weight = "normal" +heading_font_weight = "700" + +# ── Text — NTT ink scale ── +text_color = "#2e404d" +muted_text_color = "#586671" + +# ── Surfaces — white content on a soft neutral canvas ── +background_color = "#f4f5f6" +content_background_color = "#ffffff" +surface_color = "#ffffff" +card_background_color = "#f8f8f8" +border_color = "#d5d9db" +border_radius = "10px" + +# ── Accents — Future Blue ── +primary_color = "#0072bc" +accent_color = "#0072bc" +focus_border_color = "#0072bc" +hover_background_color = "#eef5fb" +selected_background_color = "#dcecfa" + +# ── Sidebar — clean white, hairline divider ── +sidebar_background_color = "#ffffff" +sidebar_text_color = "#2e404d" +sidebar_title_color = "#151d2c" +sidebar_shadow = "1px 0 0 #d5d9db" + +# ── Top bar — deep NTT navy ── +topbar_background_color = "#151d2c" +topbar_text_color = "#ffffff" +topbar_border_color = "rgba(255,255,255,0.08)" + +# ── Footer ── +footer_background_color = "#ffffff" +footer_text_color = "#586671" +footer_border_color = "#d5d9db" + +# ── Run button — subtle brand-blue gradient ── +run_button_background = "linear-gradient(180deg, #0087dc 0%, #0072bc 100%)" +run_button_background_hover = "linear-gradient(180deg, #1a93e6 0%, #0079c8 100%)" +run_button_text_color = "#ffffff" + +# ── Depth — soft, navy-tinted shadows ── +shadow_sm = "0 1px 2px rgba(21,29,44,0.05)" +shadow_md = "0 6px 18px rgba(21,29,44,0.08)" +shadow_lg = "0 16px 40px rgba(21,29,44,0.10)" diff --git a/studies/202607_CX_AI_Diagnostic/configs/base.yaml b/studies/202607_CX_AI_Diagnostic/configs/base.yaml new file mode 100644 index 0000000..b4f30d1 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/configs/base.yaml @@ -0,0 +1,184 @@ +# CX AI Advisory Diagnostic — universal config (industry-independent). +# +# This file is the diagnostic's *_VERBATIM anchor (Mercury Notebook Pattern): +# the competency model, level descriptors, and capping heuristic that every +# industry overlay extends. Editing wording here is editing the instrument — +# do it deliberately, and re-run tests + notebooks afterwards. + +version: "1.0" + +dimensions: + - id: strategy_value + name: "Strategy & Value" + - id: foundations + name: "Foundations" + - id: delivery + name: "Delivery" + - id: sustain + name: "Sustain" + +competencies: + # ── Strategy & Value ───────────────────────────────────────────────── + - id: automation_ai_strategy + dimension: strategy_value + name: "Automation & AI Strategy" + description: "Is there a written thesis for why AI, where, and what it changes about the operating model?" + failure_vignette: "We're doing AI because the CEO read an article." + level_descriptors: + 1: "No thesis. AI driven by executive impulse or vendor pitch." + 2: "Aspirational vision, no operating model implications defined." + 3: "Documented strategy, partial linkage to operating model." + 4: "Strategy drives portfolio decisions and operating model changes." + 5: "Strategy is reviewed quarterly; operating model evolves with capability." + + - id: value_realization + dimension: strategy_value + name: "Value Realization" + description: "Are AI benefits defined before investment, measured after go-live, and actually harvested?" + failure_vignette: "The chatbot saved us four million dollars — nobody can say where it went." + level_descriptors: + 1: "No benefit definition. Success is anecdote and vendor slideware." + 2: "Business cases exist pre-investment; nobody measures after go-live." + 3: "Benefits tracked for flagship initiatives; harvesting is ad hoc." + 4: "Standard value framework; benefits measured and attributed per initiative." + 5: "Value realization steers the portfolio: funding follows measured returns." + + - id: executive_alignment + dimension: strategy_value + name: "Executive Alignment" + description: "Do the executives who own budget, operations, and technology pull in the same direction on AI?" + failure_vignette: "The CIO and the COO each run their own AI program — neither knows the other's roadmap." + level_descriptors: + 1: "No accountable executive. AI initiatives appear wherever budget leaks." + 2: "One sponsor evangelizes; peer executives are indifferent or resistant." + 3: "Named executive owner; cross-functional steering exists on paper." + 4: "Steering meets and decides; budget and priorities move as one portfolio." + 5: "AI accountability sits in executive scorecards and compensation." + + # ── Foundations ────────────────────────────────────────────────────── + - id: process_discovery + dimension: foundations + name: "Process Discovery" + description: "Do you know, at task level, how customer-facing work actually flows today?" + failure_vignette: "We automated the process as documented — it turns out nobody follows it." + level_descriptors: + 1: "Processes undocumented; the knowledge lives in agents' heads." + 2: "High-level process maps exist — stale and aspirational." + 3: "Priority journeys mapped at task level with volumes and handle data." + 4: "Discovery is instrumented (mining, analytics); maps reflect observed work." + 5: "Continuous process intelligence feeds an automation pipeline." + + - id: data_readiness + dimension: foundations + name: "Data Readiness" + description: "Is the data AI needs — knowledge, interactions, customer context — accessible, clean, and governed?" + failure_vignette: "The bot's knowledge base is a SharePoint folder last updated two reorgs ago." + level_descriptors: + 1: "Data siloed and unmanaged; no owner, no quality measures." + 2: "Key sources identified; access is manual and quality unknown." + 3: "Priority data consolidated and cleansed for first use cases; stewardship assigned." + 4: "Governed pipelines feed AI in production; quality is monitored." + 5: "Data products with SLAs; a new use case onboards in days, not quarters." + + - id: technical_architecture + dimension: foundations + name: "Technical Architecture" + description: "Can your platform stack integrate, orchestrate, and scale AI services safely?" + failure_vignette: "Every new bot needs a six-month integration project and its own credentials spreadsheet." + level_descriptors: + 1: "Legacy estate; point-to-point integrations; no API layer." + 2: "Some APIs exist; each AI effort builds bespoke plumbing." + 3: "Reference architecture defined; shared integration layer for priority systems." + 4: "Platform approach: reusable services, identity, and observability across AI workloads." + 5: "Composable architecture; new AI capability ships on a paved road." + + # ── Delivery ───────────────────────────────────────────────────────── + - id: use_case_prioritization + dimension: delivery + name: "Use Case Prioritization" + description: "Is there a managed portfolio that chooses AI work by value and feasibility?" + failure_vignette: "We have forty AI ideas on a whiteboard, and the loudest stakeholder goes first." + level_descriptors: + 1: "No pipeline; initiatives start on executive impulse." + 2: "An idea list exists; no scoring, no sequencing." + 3: "Value and feasibility scoring; a prioritized backlog is reviewed." + 4: "Portfolio managed against capacity and dependencies; stop/pivot rules are applied." + 5: "The portfolio rebalances continuously on measured value and capability growth." + + - id: delivery_capability + dimension: delivery + name: "Delivery Capability" + description: "Can you take an AI use case from concept to production, repeatably?" + failure_vignette: "Every pilot succeeds; nothing ever reaches production." + level_descriptors: + 1: "No delivery method for AI; experiments die in the lab." + 2: "Vendor-led one-off projects; nothing reusable remains." + 3: "A standard delivery path exists; a few use cases run in production." + 4: "Product teams ship AI iteratively; reusable components accelerate delivery." + 5: "Factory model: concept-to-production in weeks, with automated quality gates." + + - id: talent_and_skills + dimension: delivery + name: "Talent & Skills" + description: "Are the skills AI delivery needs — conversation design, prompting, data, MLOps — in the right seats?" + failure_vignette: "Our bot team is one hero contractor whose contract ends in March." + level_descriptors: + 1: "No AI-relevant skills in-house; total vendor dependence." + 2: "Isolated enthusiasts self-teach; no roles or paths defined." + 3: "Core roles staffed for current initiatives; a training program has started." + 4: "Skills strategy: career paths, internal academy, knowledge-transfer clauses with vendors." + 5: "Talent is a differentiator: bench depth, low key-person risk, a magnet for hires." + + # ── Sustain ────────────────────────────────────────────────────────── + - id: ai_operations + dimension: sustain + name: "AI Operations" + description: "Once AI is live, who watches it, tunes it, and fixes it — with what telemetry?" + failure_vignette: "Containment fell for three weeks before anyone noticed — a menu change had broken the intents." + level_descriptors: + 1: "No monitoring; failures surface as customer complaints." + 2: "Manual spot checks; tuning happens when someone escalates." + 3: "Dashboards for containment and accuracy; scheduled tuning cycles." + 4: "Full observability: drift alerts, feedback loops, a named run team." + 5: "Self-optimizing operations; automated retraining inside governed guardrails." + + - id: change_adoption + dimension: sustain + name: "Change & Adoption" + description: "Are agents, supervisors, and customers brought along — or does AI happen to them?" + failure_vignette: "Agents learned about the copilot from the go-live email — they've been closing it ever since." + level_descriptors: + 1: "No change effort; adoption is assumed." + 2: "Announcement-and-training-deck change; adoption unmeasured." + 3: "Structured change program for major rollouts; adoption tracked." + 4: "Co-design with the front line; champions network; adoption is a launch KPI." + 5: "Change muscle is institutional; the front line pulls the roadmap forward." + + - id: governance_and_risk + dimension: sustain + name: "Governance & Risk" + description: "Are AI risk, compliance, and ethics governed — at the speed production AI moves?" + failure_vignette: "Legal found out about the voice bot when a customer complaint reached the regulator." + level_descriptors: + 1: "No AI governance; risk is handled after incidents." + 2: "Generic IT policies stretched over AI; approvals ad hoc and slow." + 3: "AI policy and a review board for high-risk use cases." + 4: "Risk-tiered governance embedded in delivery; audit trails standard." + 5: "Governance is an accelerator: pre-approved patterns, continuous compliance." + +# ── Value capping heuristic ──────────────────────────────────────────── +# Applied to the WEAKEST foundational competency score: the fraction of +# theoretical annual value an organization at that level can realistically +# capture. All bands are ranges — never point estimates. +capping_heuristic: + 1: {realized_low: 0.00, realized_high: 0.15} + 2: {realized_low: 0.25, realized_high: 0.40} + 3: {realized_low: 0.50, realized_high: 0.65} + 4: {realized_low: 0.65, realized_high: 0.85} + 5: {realized_low: 0.80, realized_high: 1.00} + +# Which competencies act as "foundational" — their weakness caps everything. +foundational_competencies: + - process_discovery + - data_readiness + - technical_architecture diff --git a/studies/202607_CX_AI_Diagnostic/configs/contact_center.yaml b/studies/202607_CX_AI_Diagnostic/configs/contact_center.yaml new file mode 100644 index 0000000..23b2b48 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/configs/contact_center.yaml @@ -0,0 +1,62 @@ +# CX AI Advisory Diagnostic — contact-center industry overlay. +# +# Value-driver ranges are 🟡 placeholder benchmarks pending citation work +# (see docs/build_spec_v1.md §12): before running with a real client, back +# each range with public sources or "based on N engagements" framing. +# `value_formula` strings are documentation of the math implemented in +# diaglib/value_math.py (dispatched on `kind`) — they are carried into +# exports verbatim, not evaluated. + +extends: base +industry: contact_center +display_name: "Contact Center" + +value_drivers: + - id: deflection_lift + name: "Deflection / containment improvement" + kind: containment_lift + baseline_field: current_containment_rate + lift_range_pts_low: 0.15 + lift_range_pts_high: 0.35 + value_formula: "annual_contact_volume * lift_pts * blended_cost_per_contact" + source: "Public benchmarks; virtual agent maturity studies" # 🟡 placeholder + + - id: aht_reduction + name: "Average handle time reduction" + kind: aht_reduction + baseline_field: average_handle_time_seconds + reduction_pct_low: 0.15 + reduction_pct_high: 0.25 + value_formula: "annual_contact_volume * (baseline_seconds * reduction_pct) * (blended_cost_per_contact / baseline_seconds)" + source: "Agent assist / copilot case data" # 🟡 placeholder + + - id: attrition_reduction + name: "Attrition reduction" + kind: attrition_reduction + baseline_field: annual_attrition_rate + reduction_pct_low: 0.10 + reduction_pct_high: 0.20 + cost_per_replacement_default: 15000 # 🟡 industry-tunable per engagement + value_formula: "agent_headcount * (annual_attrition_rate * reduction_pct) * cost_per_replacement" + source: "Job quality / copilot studies" # 🟡 placeholder + +# ── Unlock costs ─────────────────────────────────────────────────────── +# Rough cost/time ranges per one-level lift, per foundational competency. +# 🟡 estimates — sparse is OK for MVP; a missing lift renders as +# "cost not configured" in the unlock sequence rather than a guess. +unlock_costs: + data_readiness: + lift_1_to_2: {cost_low: 150000, cost_high: 300000, weeks: 8} + lift_2_to_3: {cost_low: 300000, cost_high: 600000, weeks: 12} + lift_3_to_4: {cost_low: 400000, cost_high: 800000, weeks: 16} + lift_4_to_5: {cost_low: 500000, cost_high: 1000000, weeks: 20} + process_discovery: + lift_1_to_2: {cost_low: 80000, cost_high: 160000, weeks: 6} + lift_2_to_3: {cost_low: 120000, cost_high: 250000, weeks: 8} + lift_3_to_4: {cost_low: 150000, cost_high: 300000, weeks: 10} + lift_4_to_5: {cost_low: 200000, cost_high: 400000, weeks: 12} + technical_architecture: + lift_1_to_2: {cost_low: 100000, cost_high: 200000, weeks: 8} + lift_2_to_3: {cost_low: 200000, cost_high: 400000, weeks: 10} + lift_3_to_4: {cost_low: 250000, cost_high: 500000, weeks: 12} + lift_4_to_5: {cost_low: 350000, cost_high: 700000, weeks: 16} diff --git a/studies/202607_CX_AI_Diagnostic/configs/financial_services.yaml b/studies/202607_CX_AI_Diagnostic/configs/financial_services.yaml new file mode 100644 index 0000000..3ab81fb --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/configs/financial_services.yaml @@ -0,0 +1,14 @@ +# CX AI Advisory Diagnostic — financial-services overlay (STUB, MVP). +# +# The competency model and capping heuristic come from base.yaml unchanged. +# Value drivers and unlock costs are not yet configured for this industry: +# selecting it in the notebook scores capability normally but computes no +# value-at-stake (an on-stage notice says so). Populate value_drivers and +# unlock_costs before using this config with a client. + +extends: base +industry: financial_services +display_name: "Financial Services (stub)" + +value_drivers: [] +unlock_costs: {} diff --git a/studies/202607_CX_AI_Diagnostic/diaglib/__init__.py b/studies/202607_CX_AI_Diagnostic/diaglib/__init__.py new file mode 100644 index 0000000..e7fd636 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/diaglib/__init__.py @@ -0,0 +1,62 @@ +"""diaglib — the CX AI Advisory Diagnostic engine (Mercury Notebook Pattern). + +All math and data contracts live here; the notebook only arranges and +renders. See docs/build_spec_v1.md for the instrument's specification. +""" + +from .config import configs_dir, list_industries, load_config +from .export import ( + CSV_COLUMNS, + engagement_json, + load_engagement, + scores_dataframe, + write_exports, +) +from .models import ( + BASELINE_FIELDS, + CONFIDENCE_ICON, + Competency, + CompetencyScore, + DiagnosticConfig, + DriverValue, + Engagement, + OperationalBaseline, + Participant, + UnlockMove, + ValueAtStake, +) +from .scoring import ( + build_engagement, + build_scores, + dimension_rollup, + evidence_coverage, + heatmap_grid, + make_engagement_id, + parse_participants, +) +from .staging import backstage, on_stage +from .value_math import ( + MONTHS_18, + binding_constraints, + driver_value, + html_money, + money, + unlock_sequence, + value_at_stake, + weakest_foundational_score, +) +from .visuals import heatmap_fig, split_fig, unlock_fig, value_bands_fig + +__all__ = [ + "BASELINE_FIELDS", "CONFIDENCE_ICON", "CSV_COLUMNS", "MONTHS_18", + "Competency", "CompetencyScore", "DiagnosticConfig", "DriverValue", + "Engagement", "OperationalBaseline", "Participant", "UnlockMove", + "ValueAtStake", "backstage", "binding_constraints", "build_engagement", + "build_scores", "configs_dir", "dimension_rollup", "driver_value", + "engagement_json", "evidence_coverage", "heatmap_fig", "heatmap_grid", + "html_money", "list_industries", "load_config", "load_engagement", + "make_engagement_id", "money", "on_stage", "parse_participants", + "scores_dataframe", "split_fig", "unlock_fig", "unlock_sequence", + "value_at_stake", "value_bands_fig", "weakest_foundational_score", + "write_exports", +] diff --git a/studies/202607_CX_AI_Diagnostic/diaglib/config.py b/studies/202607_CX_AI_Diagnostic/diaglib/config.py new file mode 100644 index 0000000..74fd6f0 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/diaglib/config.py @@ -0,0 +1,77 @@ +"""Load and merge ``configs/*.yaml`` into a validated DiagnosticConfig. + +``base.yaml`` holds the industry-independent competency model; every other +YAML in the directory is an industry overlay declaring ``extends: base`` +plus its value drivers and unlock costs. Merging is shallow and explicit: +the overlay contributes industry identity, drivers, and costs; the base +contributes everything else. Overlays may not redefine the competency +model — one instrument, many industries. +""" + +from __future__ import annotations + +from pathlib import Path +from typing import Any + +import yaml + +from .models import DiagnosticConfig + +#: Overlay keys an industry file may set. Anything else (competencies, +#: capping_heuristic, …) belongs in base.yaml and is rejected loudly. +_OVERLAY_KEYS = {"extends", "industry", "display_name", "value_drivers", "unlock_costs"} + + +def configs_dir(start: Path | None = None) -> Path: + """The study's ``configs/`` directory, found from ``start`` (or CWD). + + Walks up so it works from the study root, ``notebooks/``, or ``tests/``. + """ + here = (start or Path.cwd()).resolve() + for candidate in (here, *here.parents): + d = candidate / "configs" + if (d / "base.yaml").exists(): + return d + raise FileNotFoundError("configs/base.yaml not found above " + str(here)) + + +def list_industries(directory: Path | None = None) -> list[str]: + """Industry config names (file stems), base excluded, sorted.""" + d = directory or configs_dir() + return sorted(p.stem for p in d.glob("*.yaml") if p.stem != "base") + + +def _read_yaml(path: Path) -> dict[str, Any]: + with open(path, encoding="utf-8") as fh: + data = yaml.safe_load(fh) + if not isinstance(data, dict): + raise ValueError(f"{path.name}: expected a mapping at top level") + return data + + +def load_config(industry: str, directory: Path | None = None) -> DiagnosticConfig: + """Load ``base.yaml`` + the named industry overlay, validated.""" + d = directory or configs_dir() + base = _read_yaml(d / "base.yaml") + overlay = _read_yaml(d / f"{industry}.yaml") + + if overlay.get("extends") != "base": + raise ValueError(f"{industry}.yaml must declare 'extends: base'") + stray = set(overlay) - _OVERLAY_KEYS + if stray: + raise ValueError( + f"{industry}.yaml sets base-only keys {sorted(stray)} — " + "the competency model lives in base.yaml") + + merged: dict[str, Any] = { + "version": base["version"], + "dimensions": base["dimensions"], + "competencies": base["competencies"], + "capping_heuristic": base["capping_heuristic"], + "foundational_competencies": base["foundational_competencies"], + "industry": overlay["industry"], + "display_name": overlay.get("display_name", overlay["industry"]), + "value_drivers": overlay.get("value_drivers") or [], + "unlock_costs": overlay.get("unlock_costs") or {}, + } + return DiagnosticConfig.model_validate(merged) diff --git a/studies/202607_CX_AI_Diagnostic/diaglib/export.py b/studies/202607_CX_AI_Diagnostic/diaglib/export.py new file mode 100644 index 0000000..5e1d44e --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/diaglib/export.py @@ -0,0 +1,62 @@ +"""Structured engagement exports — the JSON is the source-of-truth artifact. + +``exports/{engagement_id}.json`` — the full Engagement, serialized. +``exports/{engagement_id}.csv`` — one row per competency, for +cross-engagement spreadsheet analysis (build spec §8). +""" + +from __future__ import annotations + +import json +from pathlib import Path + +import pandas as pd + +from .models import DiagnosticConfig, Engagement + +CSV_COLUMNS = [ + "engagement_id", "client_name", "industry", "workshop_date", + "competency_id", "dimension", "score", "evidence", + "is_foundational", "is_binding_constraint", +] + + +def engagement_json(engagement: Engagement) -> str: + return json.dumps(engagement.model_dump(mode="json"), indent=2, + ensure_ascii=False) + + +def scores_dataframe(engagement: Engagement, + config: DiagnosticConfig) -> pd.DataFrame: + binding = set(engagement.computed_value.binding_constraints + if engagement.computed_value else []) + foundational = set(config.foundational_competencies) + rows = [{ + "engagement_id": engagement.engagement_id, + "client_name": engagement.client_name, + "industry": engagement.industry_config, + "workshop_date": engagement.workshop_date.isoformat(), + "competency_id": s.competency_id, + "dimension": s.dimension, + "score": s.score, + "evidence": s.evidence, + "is_foundational": s.competency_id in foundational, + "is_binding_constraint": s.competency_id in binding, + } for s in engagement.scores] + return pd.DataFrame(rows, columns=CSV_COLUMNS) + + +def write_exports(engagement: Engagement, config: DiagnosticConfig, + exports_dir: Path) -> tuple[Path, Path]: + """Write both artifacts; returns ``(json_path, csv_path)``.""" + exports_dir.mkdir(parents=True, exist_ok=True) + json_path = exports_dir / f"{engagement.engagement_id}.json" + csv_path = exports_dir / f"{engagement.engagement_id}.csv" + json_path.write_text(engagement_json(engagement), encoding="utf-8") + scores_dataframe(engagement, config).to_csv(csv_path, index=False) + return json_path, csv_path + + +def load_engagement(json_path: Path) -> Engagement: + """Reload a saved engagement for review (acceptance §10 nice-to-have).""" + return Engagement.model_validate_json(json_path.read_text(encoding="utf-8")) diff --git a/studies/202607_CX_AI_Diagnostic/diaglib/models.py b/studies/202607_CX_AI_Diagnostic/diaglib/models.py new file mode 100644 index 0000000..d4beab1 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/diaglib/models.py @@ -0,0 +1,281 @@ +"""Pydantic models — every data structure the diagnostic captures or computes. + +Two families live here: + +* **Engagement data** — what the workshop records (participants, baseline, + scores) and what the engine computes (:class:`ValueAtStake`). The + serialized :class:`Engagement` is the source-of-truth export artifact. +* **Config data** — the validated shape of ``configs/*.yaml``: the + competency model (base) and the industry overlay (drivers, unlock costs). + +Deviations from the build spec (docs/build_spec_v1.md), both additive: + +* :class:`UnlockMove` carries ``competency_ids`` (plural). When several + foundational competencies tie at the weakest level, the binding + constraint *is the set* — a single-competency move would honestly unlock + nothing. Moves are tier lifts of the whole binding set. +* :class:`ValueAtStake` also records the driver breakdown, the realization + band, and guard-rail warnings, so the export explains its own numbers. +""" + +from __future__ import annotations + +from datetime import date, datetime +from typing import Literal + +from pydantic import BaseModel, Field, field_validator, model_validator + +Function = Literal["cx", "it", "ops", "finance", "other"] +Confidence = Literal["known", "estimated", "unknown"] + +CONFIDENCE_ICON: dict[str, str] = { + "known": "🟢", "estimated": "🟡", "unknown": "🔴", +} + +#: The six numeric baseline fields collected in the workshop form. +BASELINE_FIELDS: tuple[str, ...] = ( + "annual_contact_volume", + "blended_cost_per_contact", + "agent_headcount", + "annual_attrition_rate", + "current_containment_rate", + "average_handle_time_seconds", +) + + +# ── Engagement data ────────────────────────────────────────────────── + + +class Participant(BaseModel): + name: str + role: str = "" + function: Function = "other" + + +class OperationalBaseline(BaseModel): + """Contact-center MVP fields; other industries overlay their own.""" + + annual_contact_volume: int = Field(ge=0) + blended_cost_per_contact: float = Field(ge=0) + agent_headcount: int = Field(ge=0) + annual_attrition_rate: float = Field(ge=0, le=1) + current_containment_rate: float = Field(ge=0, le=1) + average_handle_time_seconds: int = Field(ge=0) + csat_baseline: float | None = None + revenue_at_risk: float | None = None + #: Per-field confidence flags (🟢 known / 🟡 estimated / 🔴 unknown). + field_confidence: dict[str, Confidence] = Field(default_factory=dict) + + @field_validator("field_confidence") + @classmethod + def _known_fields_only(cls, v: dict[str, Confidence]) -> dict[str, Confidence]: + unknown = set(v) - set(BASELINE_FIELDS) + if unknown: + raise ValueError(f"confidence flags for unknown fields: {sorted(unknown)}") + return v + + def confidence_for(self, field: str) -> Confidence: + return self.field_confidence.get(field, "estimated") + + +class CompetencyScore(BaseModel): + competency_id: str + dimension: str + score: int = Field(ge=1, le=5) + evidence: str = "" # one line: why this score + scorer_role: str = "facilitator" # MVP: facilitator consensus + scored_at: datetime + + +class DriverValue(BaseModel): + """One value driver's theoretical annual value, as a range.""" + + driver_id: str + name: str + theoretical_low: float + theoretical_high: float + + +class UnlockMove(BaseModel): + """One move in the unlock sequence: lift the binding set one level. + + ``value_unlocked_*`` is the **annual run-rate** realizable value the + lift adds (delta of the realization band times theoretical value). + Costs are ``None`` when the config has no entry for a lift — shown as + "cost not configured", never guessed. + """ + + competency_ids: list[str] + current_level: int = Field(ge=1, le=4) + target_level: int = Field(ge=2, le=5) + est_cost_low: float | None = None + est_cost_high: float | None = None + est_weeks: int | None = None + value_unlocked_low: float + value_unlocked_high: float + note: str = "" + + @model_validator(mode="after") + def _one_level_lift(self) -> "UnlockMove": + if self.target_level != self.current_level + 1: + raise ValueError("unlock moves lift exactly one level") + return self + + +class ValueAtStake(BaseModel): + theoretical_annual_value_low: float + theoretical_annual_value_high: float + realizable_18mo_low: float + realizable_18mo_high: float + trapped_value_low: float # annual: theoretical − realizable run-rate + trapped_value_high: float + binding_constraints: list[str] # competency_ids capping realization + unlock_sequence: list[UnlockMove] + # Self-explaining extras (additive to the build spec): + weakest_foundational_score: int = Field(ge=1, le=5) + realization_factor_low: float = Field(ge=0, le=1) + realization_factor_high: float = Field(ge=0, le=1) + driver_values: list[DriverValue] = Field(default_factory=list) + warnings: list[str] = Field(default_factory=list) + + +class Engagement(BaseModel): + engagement_id: str # e.g. "acme_2026-07-19" + client_name: str + industry_config: str # which config was loaded + facilitator: str + workshop_date: date + participants: list[Participant] = Field(default_factory=list) + operational_baseline: OperationalBaseline + scores: list[CompetencyScore] = Field(default_factory=list) + computed_value: ValueAtStake | None = None + notes: str = "" + + +# ── Config data (configs/*.yaml) ───────────────────────────────────── + + +class Dimension(BaseModel): + id: str + name: str + + +class Competency(BaseModel): + id: str + dimension: str + name: str + description: str + failure_vignette: str + level_descriptors: dict[int, str] + + @field_validator("level_descriptors") + @classmethod + def _five_levels(cls, v: dict[int, str]) -> dict[int, str]: + if set(v) != {1, 2, 3, 4, 5}: + raise ValueError("level_descriptors must cover exactly levels 1–5") + return v + + +class CappingBand(BaseModel): + realized_low: float = Field(ge=0, le=1) + realized_high: float = Field(ge=0, le=1) + + @model_validator(mode="after") + def _ordered(self) -> "CappingBand": + if self.realized_low > self.realized_high: + raise ValueError("realized_low > realized_high") + return self + + +class ValueDriver(BaseModel): + """A configured value driver. ``kind`` selects the math in + value_math.py; ``value_formula`` documents it verbatim in exports.""" + + id: str + name: str + kind: Literal["containment_lift", "aht_reduction", "attrition_reduction"] + baseline_field: str + value_formula: str = "" + source: str = "" + # kind-specific parameters (validated in value_math dispatch): + lift_range_pts_low: float | None = None + lift_range_pts_high: float | None = None + reduction_pct_low: float | None = None + reduction_pct_high: float | None = None + cost_per_replacement_default: float | None = None + + +class LiftCost(BaseModel): + cost_low: float = Field(ge=0) + cost_high: float = Field(ge=0) + weeks: int = Field(ge=0) + + @model_validator(mode="after") + def _ordered(self) -> "LiftCost": + if self.cost_low > self.cost_high: + raise ValueError("cost_low > cost_high") + return self + + +class DiagnosticConfig(BaseModel): + """base.yaml merged with one industry overlay — what the engine consumes.""" + + version: str + industry: str + display_name: str + dimensions: list[Dimension] + competencies: list[Competency] + capping_heuristic: dict[int, CappingBand] + foundational_competencies: list[str] + value_drivers: list[ValueDriver] = Field(default_factory=list) + #: unlock_costs[competency_id]["lift_2_to_3"] -> LiftCost + unlock_costs: dict[str, dict[str, LiftCost]] = Field(default_factory=dict) + + @model_validator(mode="after") + def _consistent(self) -> "DiagnosticConfig": + comp_ids = [c.id for c in self.competencies] + if len(comp_ids) != len(set(comp_ids)): + raise ValueError("duplicate competency ids") + dim_ids = {d.id for d in self.dimensions} + for c in self.competencies: + if c.dimension not in dim_ids: + raise ValueError(f"competency {c.id}: unknown dimension {c.dimension}") + missing = set(self.foundational_competencies) - set(comp_ids) + if missing: + raise ValueError(f"foundational competencies not defined: {sorted(missing)}") + if set(self.capping_heuristic) != {1, 2, 3, 4, 5}: + raise ValueError("capping_heuristic must cover exactly scores 1–5") + for lo, hi in zip(sorted(self.capping_heuristic), sorted(self.capping_heuristic)[1:]): + a, b = self.capping_heuristic[lo], self.capping_heuristic[hi] + if a.realized_low > b.realized_low or a.realized_high > b.realized_high: + raise ValueError("capping_heuristic must be non-decreasing in score") + for cid, lifts in self.unlock_costs.items(): + if cid not in comp_ids: + raise ValueError(f"unlock_costs for unknown competency {cid}") + for key in lifts: + if not _valid_lift_key(key): + raise ValueError(f"unlock_costs[{cid}]: bad lift key {key!r}") + return self + + def competency(self, competency_id: str) -> Competency: + for c in self.competencies: + if c.id == competency_id: + return c + raise KeyError(competency_id) + + def dimension_name(self, dimension_id: str) -> str: + for d in self.dimensions: + if d.id == dimension_id: + return d.name + raise KeyError(dimension_id) + + def lift_cost(self, competency_id: str, from_level: int) -> LiftCost | None: + return self.unlock_costs.get(competency_id, {}).get( + f"lift_{from_level}_to_{from_level + 1}") + + +def _valid_lift_key(key: str) -> bool: + parts = key.split("_") # "lift", a, "to", b — one-level lifts only + return (len(parts) == 4 and parts[0] == "lift" and parts[2] == "to" + and parts[1].isdigit() and parts[3].isdigit() + and int(parts[3]) == int(parts[1]) + 1 and 1 <= int(parts[1]) <= 4) diff --git a/studies/202607_CX_AI_Diagnostic/diaglib/scoring.py b/studies/202607_CX_AI_Diagnostic/diaglib/scoring.py new file mode 100644 index 0000000..11b8af6 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/diaglib/scoring.py @@ -0,0 +1,133 @@ +"""Score aggregation, gap analysis, and engagement assembly. + +Everything the notebook needs between raw widget values and the engine's +value math lives here — the notebook itself computes nothing. +""" + +from __future__ import annotations + +import re +from datetime import date, datetime +from typing import get_args + +from .models import ( + CompetencyScore, + DiagnosticConfig, + Engagement, + Function, + OperationalBaseline, + Participant, + ValueAtStake, +) + +FUNCTIONS: tuple[str, ...] = get_args(Function) + + +# ── Engagement identity ────────────────────────────────────────────── + + +def make_engagement_id(client_name: str, workshop_date: date) -> str: + """``"Acme Corp!" + 2026-07-19 -> "acme_corp_2026-07-19"``.""" + slug = re.sub(r"[^a-z0-9]+", "_", client_name.lower()).strip("_") or "client" + return f"{slug}_{workshop_date.isoformat()}" + + +def parse_participants(text: str) -> list[Participant]: + """Parse ``"Name | Role | function; Name | Role | function"``. + + Forgiving by design — the facilitator types this live. Missing parts + default (role empty, function ``other``); unknown functions map to + ``other`` rather than erroring mid-workshop. + """ + participants: list[Participant] = [] + for entry in text.split(";"): + parts = [p.strip() for p in entry.split("|")] + if not parts or not parts[0]: + continue + function = parts[2].lower() if len(parts) > 2 else "other" + participants.append(Participant( + name=parts[0], + role=parts[1] if len(parts) > 1 else "", + function=function if function in FUNCTIONS else "other", + )) + return participants + + +# ── Scores ─────────────────────────────────────────────────────────── + + +def build_scores(config: DiagnosticConfig, raw: dict[str, tuple[int, str]], + scored_at: datetime, + scorer_role: str = "facilitator") -> list[CompetencyScore]: + """``raw[competency_id] = (score, evidence)`` → validated scores, config order.""" + missing = [c.id for c in config.competencies if c.id not in raw] + if missing: + raise ValueError(f"unscored competencies: {missing}") + return [ + CompetencyScore( + competency_id=c.id, dimension=c.dimension, + score=raw[c.id][0], evidence=raw[c.id][1].strip(), + scorer_role=scorer_role, scored_at=scored_at, + ) + for c in config.competencies + ] + + +def dimension_rollup(config: DiagnosticConfig, + scores: list[CompetencyScore]) -> list[tuple[str, str, float]]: + """``(dimension_id, dimension_name, mean score)`` per dimension, config order.""" + by_dim: dict[str, list[int]] = {d.id: [] for d in config.dimensions} + for s in scores: + by_dim[s.dimension].append(s.score) + return [(d.id, d.name, sum(v) / len(v)) + for d in config.dimensions if (v := by_dim[d.id])] + + +def evidence_coverage(scores: list[CompetencyScore]) -> tuple[int, int]: + """``(scores with evidence captured, total scores)``.""" + return sum(1 for s in scores if s.evidence), len(scores) + + +def heatmap_grid(config: DiagnosticConfig, scores: list[CompetencyScore]) -> dict: + """Pure data for the 4×3 heatmap — rows are dimensions, three + competencies per row in config order. Returned as plain lists so the + visuals layer holds no logic.""" + by_id = {s.competency_id: s for s in scores} + rows, z, text, hover = [], [], [], [] + for d in config.dimensions: + comps = [c for c in config.competencies if c.dimension == d.id] + rows.append(d.name) + z.append([by_id[c.id].score for c in comps]) + text.append([f"{by_id[c.id].score}
{c.name}" for c in comps]) + hover.append([ + f"{c.name} — level {by_id[c.id].score}
" + f"{c.level_descriptors[by_id[c.id].score]}
" + f"{by_id[c.id].evidence or 'no evidence captured'}" + for c in comps + ]) + return {"rows": rows, "z": z, "text": text, "hover": hover, + "cols": ["", "", ""]} + + +# ── Assembly ───────────────────────────────────────────────────────── + + +def build_engagement(*, config: DiagnosticConfig, client_name: str, + facilitator: str, workshop_date: date, + participants: list[Participant], + baseline: OperationalBaseline, + scores: list[CompetencyScore], + computed_value: ValueAtStake | None, + notes: str = "") -> Engagement: + return Engagement( + engagement_id=make_engagement_id(client_name, workshop_date), + client_name=client_name.strip() or "Unnamed client", + industry_config=config.industry, + facilitator=facilitator.strip(), + workshop_date=workshop_date, + participants=participants, + operational_baseline=baseline, + scores=scores, + computed_value=computed_value, + notes=notes, + ) diff --git a/studies/202607_CX_AI_Diagnostic/diaglib/staging.py b/studies/202607_CX_AI_Diagnostic/diaglib/staging.py new file mode 100644 index 0000000..2ec7bec --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/diaglib/staging.py @@ -0,0 +1,29 @@ +""" +Stage vs backstage — is this notebook render stakeholder-facing? + +The Mercury CLI (``mercury --working-dir …``) exports ``MERCURY_CONFIG_DIR`` +into the server process so the widget library can locate ``config.toml`` +(see ``mercury/config.py``); every kernel that server spawns inherits it. +JupyterLab and nbconvert kernels don't have it. That makes the variable a +reliable signal for "the audience is looking" (the stage) versus an +analyst session or a headless export run (backstage). + +Diagnostics routed through :func:`backstage` stay visible in JupyterLab +and land in the nbconvert exports (where the machine-readable appendix +must appear for LLM consumption) but never render in the Mercury app. +""" + +from __future__ import annotations + +import os + + +def on_stage() -> bool: + """True when running under the Mercury app (stakeholder-facing).""" + return os.getenv("MERCURY_CONFIG_DIR") is not None + + +def backstage(*args, **kwargs) -> None: + """``print`` that renders only backstage (JupyterLab, nbconvert).""" + if not on_stage(): + print(*args, **kwargs) diff --git a/studies/202607_CX_AI_Diagnostic/diaglib/value_math.py b/studies/202607_CX_AI_Diagnostic/diaglib/value_math.py new file mode 100644 index 0000000..db150be --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/diaglib/value_math.py @@ -0,0 +1,228 @@ +"""Value-at-stake math: driver values, capability capping, unlock sequence. + +The pipeline (build spec §6): + +1. Each configured value driver yields a theoretical annual value range + from the operational baseline (dispatch on ``driver.kind``). +2. Theoretical annual value = sum of drivers. +3. The **weakest foundational competency score** selects a realization + band from the capping heuristic. +4. ``realizable_18mo = theoretical × realization_factor × 1.5`` + (18 months of annual run-rate). +5. Trapped value (annual) = theoretical − realizable run-rate. Range + pairing is conservative-consistent: the low trapped estimate assumes + the low theoretical *and* the high realization factor, and vice versa. +6. Binding constraints = every foundational competency sitting at the + weakest score. +7. Unlock sequence = up to three **tier lifts**: raise the whole binding + set one level, recompute the band, attribute the delta. When several + competencies tie at the weakest level a single-competency lift would + honestly unlock nothing — the set is the move (see UnlockMove docs). + +Guard rails: every output is a range; 🔴-unknown inputs raise warnings on +the result; money *display* is capped at two significant figures +(:func:`money`) while raw floats stay exact in exports. +""" + +from __future__ import annotations + +from .models import ( + CompetencyScore, + DiagnosticConfig, + DriverValue, + OperationalBaseline, + UnlockMove, + ValueAtStake, + ValueDriver, +) + +#: 18 months expressed in years of annual run-rate. +MONTHS_18 = 1.5 + +#: How many unlock moves the sequence proposes. +MAX_UNLOCK_MOVES = 3 + + +# ── Money display (guard rail: ≤ 2 significant figures) ────────────── + + +def _round_2sf(v: float) -> float: + if v == 0: + return 0.0 + from math import floor, log10 + exp = floor(log10(abs(v))) + return round(v, -exp + 1) + + +def money(v: float) -> str: + """House money format, capped at two significant figures: $2.5M, $950K.""" + sign, a = ("-" if v < 0 else ""), _round_2sf(abs(v)) + if a >= 1e6: + m = a / 1e6 + return f"{sign}${m:,.1f}M" if m < 10 else f"{sign}${m:,.0f}M" + if a >= 1e3: + return f"{sign}${a / 1e3:,.0f}K" + return f"{sign}${a:,.0f}" + + +def html_money(v: float) -> str: + """Plotly text with two or more bare ``$`` triggers MathJax math mode — + annotations holding several amounts must use the HTML entity instead.""" + return money(v).replace("$", "$") + + +# ── Driver math (dispatch on kind) ─────────────────────────────────── + + +def driver_value(driver: ValueDriver, baseline: OperationalBaseline) -> DriverValue: + """Theoretical annual value range for one configured driver.""" + if driver.kind == "containment_lift": + if driver.lift_range_pts_low is None or driver.lift_range_pts_high is None: + raise ValueError(f"driver {driver.id}: containment_lift needs lift_range_pts_low/high") + low = baseline.annual_contact_volume * driver.lift_range_pts_low \ + * baseline.blended_cost_per_contact + high = baseline.annual_contact_volume * driver.lift_range_pts_high \ + * baseline.blended_cost_per_contact + elif driver.kind == "aht_reduction": + # volume × (AHT × pct) seconds saved × ($/contact ÷ AHT) per second + # — the baseline AHT cancels: volume × $/contact × pct. + if driver.reduction_pct_low is None or driver.reduction_pct_high is None: + raise ValueError(f"driver {driver.id}: aht_reduction needs reduction_pct_low/high") + low = baseline.annual_contact_volume * baseline.blended_cost_per_contact \ + * driver.reduction_pct_low + high = baseline.annual_contact_volume * baseline.blended_cost_per_contact \ + * driver.reduction_pct_high + elif driver.kind == "attrition_reduction": + if driver.reduction_pct_low is None or driver.reduction_pct_high is None: + raise ValueError(f"driver {driver.id}: attrition_reduction needs reduction_pct_low/high") + cost_per_replacement = driver.cost_per_replacement_default or 0.0 + low = baseline.agent_headcount * baseline.annual_attrition_rate \ + * driver.reduction_pct_low * cost_per_replacement + high = baseline.agent_headcount * baseline.annual_attrition_rate \ + * driver.reduction_pct_high * cost_per_replacement + else: # pragma: no cover — Literal already restricts kinds + raise ValueError(f"driver {driver.id}: unknown kind {driver.kind}") + return DriverValue(driver_id=driver.id, name=driver.name, + theoretical_low=low, theoretical_high=high) + + +# ── Capping ────────────────────────────────────────────────────────── + + +def weakest_foundational_score(config: DiagnosticConfig, + scores: list[CompetencyScore]) -> int: + by_id = {s.competency_id: s.score for s in scores} + missing = [c for c in config.foundational_competencies if c not in by_id] + if missing: + raise ValueError(f"foundational competencies unscored: {missing}") + return min(by_id[c] for c in config.foundational_competencies) + + +def binding_constraints(config: DiagnosticConfig, + scores: list[CompetencyScore]) -> list[str]: + """Foundational competencies sitting at the weakest score, config order.""" + weakest = weakest_foundational_score(config, scores) + by_id = {s.competency_id: s.score for s in scores} + return [c for c in config.foundational_competencies if by_id[c] == weakest] + + +# ── Unlock sequence (tier lifts of the binding set) ────────────────── + + +def _tier_move(config: DiagnosticConfig, level: int, members: list[str], + th_low: float, th_high: float) -> UnlockMove: + band_now = config.capping_heuristic[level] + band_next = config.capping_heuristic[level + 1] + costs = {m: config.lift_cost(m, level) for m in members} + missing = [m for m, c in costs.items() if c is None] + note = "" + if len(members) > 1: + note = "joint lift — the tied competencies must move together to shift the cap" + if missing: + note = (note + "; " if note else "") + \ + f"cost not configured for: {', '.join(missing)}" + have_all = not missing + return UnlockMove( + competency_ids=members, + current_level=level, + target_level=level + 1, + est_cost_low=sum(c.cost_low for c in costs.values() if c) if have_all else None, + est_cost_high=sum(c.cost_high for c in costs.values() if c) if have_all else None, + est_weeks=max((c.weeks for c in costs.values() if c), default=None) if have_all else None, + value_unlocked_low=th_low * (band_next.realized_low - band_now.realized_low), + value_unlocked_high=th_high * (band_next.realized_high - band_now.realized_high), + note=note, + ) + + +def unlock_sequence(config: DiagnosticConfig, scores: list[CompetencyScore], + th_low: float, th_high: float, + max_moves: int = MAX_UNLOCK_MOVES) -> list[UnlockMove]: + """Up to ``max_moves`` sequential tier lifts of the binding set. + + Each move lifts every foundational competency at the current weakest + level by one level (weeks = the longest workstream, run in parallel; + costs summed). Value unlocked is the annual realizable delta from the + capping-band shift. Moves stay in sequence order — each one is the + prerequisite of the next, so ranking them against each other would be + meaningless; the ratio walk (value/cost declining) is the story. + """ + if th_low == 0 and th_high == 0: + return [] + current = {s.competency_id: s.score for s in scores + if s.competency_id in config.foundational_competencies} + moves: list[UnlockMove] = [] + for _ in range(max_moves): + level = min(current.values()) + if level >= 5: + break + members = [c for c in config.foundational_competencies + if current[c] == level] + moves.append(_tier_move(config, level, members, th_low, th_high)) + for m in members: + current[m] = level + 1 + return moves + + +# ── The full computation ───────────────────────────────────────────── + + +def value_at_stake(config: DiagnosticConfig, baseline: OperationalBaseline, + scores: list[CompetencyScore]) -> ValueAtStake: + """Steps 1–8 of the build spec, as one call. See module docstring.""" + drivers = [driver_value(d, baseline) for d in config.value_drivers] + th_low = sum(d.theoretical_low for d in drivers) + th_high = sum(d.theoretical_high for d in drivers) + + weakest = weakest_foundational_score(config, scores) + band = config.capping_heuristic[weakest] + + warnings: list[str] = [] + if not config.value_drivers: + warnings.append( + f"config '{config.industry}' has no value drivers — " + "value-at-stake is zero (stub config)") + used_fields = sorted({d.baseline_field for d in config.value_drivers} + | ({"annual_contact_volume", "blended_cost_per_contact"} + if config.value_drivers else set())) + for f in used_fields: + if baseline.confidence_for(f) == "unknown": + warnings.append( + f"baseline input '{f}' is flagged 🔴 unknown — " + "the ranges below inherit that uncertainty") + + return ValueAtStake( + theoretical_annual_value_low=th_low, + theoretical_annual_value_high=th_high, + realizable_18mo_low=th_low * band.realized_low * MONTHS_18, + realizable_18mo_high=th_high * band.realized_high * MONTHS_18, + trapped_value_low=th_low * (1 - band.realized_high), + trapped_value_high=th_high * (1 - band.realized_low), + binding_constraints=binding_constraints(config, scores), + unlock_sequence=unlock_sequence(config, scores, th_low, th_high), + weakest_foundational_score=weakest, + realization_factor_low=band.realized_low, + realization_factor_high=band.realized_high, + driver_values=drivers, + warnings=warnings, + ) diff --git a/studies/202607_CX_AI_Diagnostic/diaglib/visuals.py b/studies/202607_CX_AI_Diagnostic/diaglib/visuals.py new file mode 100644 index 0000000..6884b0a --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/diaglib/visuals.py @@ -0,0 +1,208 @@ +"""Plotly figure builders — presentation only, consuming engine outputs. + +Chart chrome follows the house dataviz rules (see the repo dataviz +reference and docs/brand.md): recessive grid and axes, ink text tokens, +fixed entity→color assignments so a color means one thing across every +figure, 2px surface gaps between adjacent fills, selective direct labels, +one axis per chart. Room-facing: sized and typed to hold attention on a +shared screen, not for print. +""" + +from __future__ import annotations + +import plotly.graph_objects as go + +from .models import DiagnosticConfig, ValueAtStake +from .value_math import html_money + +# ── Chrome (dataviz reference palette, light surface) ──────────────── +INK, INK2, MUTED = "#0b0b0b", "#52514e", "#898781" +SURFACE, GRID, BASELINE = "#fcfcfb", "#e1e0d9", "#c3c2b7" +FONT_STACK = 'system-ui, -apple-system, "Segoe UI", sans-serif' + +# Fixed entity colors — color follows the entity across every figure. +THEORETICAL = "#9ec5f4" # light blue: the outer envelope +REALIZABLE = "#2a78d6" # blue: what capability can actually capture +TRAPPED = "#eda100" # amber: value the capability gap strands +COST = "#e34948" # red: unlock investment +UNLOCKED = "#1baf7a" # aqua-green: unlock payoff + +# Diverging maturity scale, centered on level 3 — soft poles so ink text +# stays readable in every cell (two hues + neutral midpoint, never rainbow). +SCORE_SCALE = [ + (0.0, "#ef8a76"), (0.5, "#f0efe9"), (1.0, "#57c993"), +] + + +def diag_layout(fig: go.Figure, title: str, subtitle: str | None = None, + height: int = 440) -> go.Figure: + t = f"{title}" + if subtitle: + t += f"
{subtitle}" + fig.update_layout( + title=dict(text=t, font=dict(size=16, color=INK), x=0.02, xanchor="left"), + paper_bgcolor=SURFACE, plot_bgcolor=SURFACE, + font=dict(family=FONT_STACK, size=13, color=INK2), + legend=dict(orientation="h", yanchor="top", y=-0.12, x=0, + font=dict(size=11, color=INK2)), + height=height, margin=dict(t=70, r=30, b=60, l=70), + ) + return fig + + +# ── 1 · Capability heatmap (4 dimensions × 3 competencies) ─────────── + + +def heatmap_fig(grid: dict) -> go.Figure: + """``grid`` comes from scoring.heatmap_grid — pure data in.""" + n_rows = len(grid["rows"]) + fig = go.Figure(go.Heatmap( + z=grid["z"], text=grid["text"], customdata=grid["hover"], + x=list(range(len(grid["cols"]))), y=grid["rows"], + zmin=1, zmax=5, colorscale=SCORE_SCALE, showscale=False, + texttemplate="%{text}", textfont=dict(size=13, color=INK), + hovertemplate="%{customdata}", + xgap=3, ygap=3, + )) + fig.update_xaxes(visible=False) + fig.update_yaxes(autorange="reversed", tickfont=dict(size=13, color=INK2), + showgrid=False) + diag_layout(fig, "Capability heatmap", + "12 competencies, levels 1–5 · hover a cell for the evidence", + height=90 * n_rows + 120) + return fig + + +# ── 2 · Value at stake (theoretical vs realizable ranges) ──────────── + + +def value_bands_fig(vas: ValueAtStake) -> go.Figure: + rows = [ + ("Theoretical value (annual)", vas.theoretical_annual_value_low, + vas.theoretical_annual_value_high, THEORETICAL), + ("Realizable over 18 months", vas.realizable_18mo_low, + vas.realizable_18mo_high, REALIZABLE), + ] + fig = go.Figure() + for label, low, high, color in rows: + fig.add_trace(go.Bar( + y=[label], x=[max(high - low, 1)], base=[low], orientation="h", + marker=dict(color=color, line=dict(width=2, color=SURFACE)), + showlegend=False, + hovertemplate=(f"{label}: {html_money(low)} – {html_money(high)}" + ""), + )) + fig.add_annotation(x=high, y=label, xanchor="left", xshift=6, + text=f"{html_money(low)} – {html_money(high)}", + showarrow=False, font=dict(size=12, color=INK)) + fig.add_annotation( + xref="paper", yref="paper", x=0.02, y=-0.32, xanchor="left", + showarrow=False, align="left", + text=(f"Trapped by the capability gap: " + f"{html_money(vas.trapped_value_low)} – " + f"{html_money(vas.trapped_value_high)} per year"), + font=dict(size=13, color=INK)) + fig.update_xaxes(tickformat="$~s", gridcolor=GRID, zeroline=False, + tickfont=dict(color=MUTED), rangemode="tozero") + fig.update_yaxes(tickfont=dict(size=13, color=INK2), showgrid=False, + autorange="reversed") # theoretical on top, then realizable + diag_layout(fig, "Value at stake", + "ranges, never points · realization capped by the weakest foundation", + height=300) + fig.update_layout(margin=dict(b=90), bargap=0.5) + return fig + + +# ── 3 · Realizable vs trapped split (scenario-consistent) ──────────── + + +def split_fig(vas: ValueAtStake) -> go.Figure: + """Each scenario bar splits its own theoretical total: realizable + run-rate vs trapped, at that scenario's realization factor.""" + scenarios = [ + ("Conservative", vas.theoretical_annual_value_low, vas.realization_factor_low), + ("Optimistic", vas.theoretical_annual_value_high, vas.realization_factor_high), + ] + labels = [s[0] for s in scenarios] + realizable = [th * r for _, th, r in scenarios] + trapped = [th * (1 - r) for _, th, r in scenarios] + fig = go.Figure([ + go.Bar(name="Realizable (annual run-rate)", y=labels, x=realizable, + orientation="h", + marker=dict(color=REALIZABLE, line=dict(width=2, color=SURFACE)), + text=[html_money(v) for v in realizable], + textposition="inside", insidetextfont=dict(color="#ffffff"), + hovertemplate="Realizable: %{x:$,.0f}%{y}"), + go.Bar(name="Trapped by capability gap", y=labels, x=trapped, + orientation="h", + marker=dict(color=TRAPPED, line=dict(width=2, color=SURFACE)), + text=[html_money(v) for v in trapped], + textposition="inside", insidetextfont=dict(color=INK), + hovertemplate="Trapped: %{x:$,.0f}%{y}"), + ]) + fig.update_layout(barmode="stack", bargap=0.5) + fig.update_xaxes(tickformat="$~s", gridcolor=GRID, zeroline=False, + tickfont=dict(color=MUTED)) + fig.update_yaxes(tickfont=dict(size=13, color=INK2), showgrid=False, + autorange="reversed") # conservative on top + diag_layout(fig, "Where the annual value goes", + "each scenario splits its own theoretical total", height=300) + fig.update_layout(legend=dict(traceorder="normal")) + return fig + + +# ── 4 · Unlock sequence (cost vs value per move) ───────────────────── + + +def _move_label(vas_move, config: DiagnosticConfig, idx: int) -> str: + """Compact tick label — full competency names live in the hover and + in the on-stage moves table (long joint-lift names don't fit ticks).""" + if len(vas_move.competency_ids) == 1: + what = config.competency(vas_move.competency_ids[0]).name + else: + what = f"joint lift ×{len(vas_move.competency_ids)}" + return (f"{idx} · {what}
" + f"level {vas_move.current_level} → {vas_move.target_level}") + + +def unlock_fig(vas: ValueAtStake, config: DiagnosticConfig) -> go.Figure: + moves = vas.unlock_sequence + labels = [_move_label(m, config, i + 1) for i, m in enumerate(moves)] + names = [" + ".join(config.competency(c).name for c in m.competency_ids) + for m in moves] + fig = go.Figure() + fig.add_trace(go.Bar( + name="Investment (range)", x=labels, + y=[(m.est_cost_high - m.est_cost_low) if m.est_cost_low is not None else 0 + for m in moves], + base=[m.est_cost_low if m.est_cost_low is not None else 0 for m in moves], + customdata=[[n, html_money(m.est_cost_low) + " – " + html_money(m.est_cost_high) + if m.est_cost_low is not None else "not configured"] + for n, m in zip(names, moves)], + marker=dict(color=COST, line=dict(width=2, color=SURFACE)), + hovertemplate="%{customdata[0]}
Investment: %{customdata[1]}", + )) + fig.add_trace(go.Bar( + name="Annual value unlocked (range)", x=labels, + y=[m.value_unlocked_high - m.value_unlocked_low for m in moves], + base=[m.value_unlocked_low for m in moves], + customdata=[[n, html_money(m.value_unlocked_low) + " – " + + html_money(m.value_unlocked_high)] + for n, m in zip(names, moves)], + marker=dict(color=UNLOCKED, line=dict(width=2, color=SURFACE)), + hovertemplate="%{customdata[0]}
Unlocked: %{customdata[1]}", + )) + for i, m in enumerate(moves): + if m.est_cost_low is None: + fig.add_annotation(x=labels[i], y=0, yanchor="bottom", + text="cost not
configured", showarrow=False, + font=dict(size=11, color=MUTED)) + fig.update_layout(barmode="group", bargap=0.35, bargroupgap=0.12) + fig.update_xaxes(tickfont=dict(size=12, color=INK2), showgrid=False, + tickangle=0) + fig.update_yaxes(tickformat="$~s", gridcolor=GRID, zerolinecolor=BASELINE, + tickfont=dict(color=MUTED)) + diag_layout(fig, "Unlock sequence", + "sequential moves — each is the prerequisite of the next", + height=420) + return fig diff --git a/studies/202607_CX_AI_Diagnostic/docs/build_spec_v1.md b/studies/202607_CX_AI_Diagnostic/docs/build_spec_v1.md new file mode 100644 index 0000000..1ddb88a --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/docs/build_spec_v1.md @@ -0,0 +1,111 @@ +# CX AI Advisory Diagnostic — Build Spec v1.0 + +> Source record for this study (received 2026-07-19, owner Robert +> Helewka). Kept verbatim in intent; §2 layout was adapted to the Mercury +> Notebook Pattern (study package `diaglib/`, generated notebook, +> `pyproject.toml` instead of requirements.txt) — see README for the +> deviations log. + +**Purpose:** Facilitator's cockpit for the CX AI Advisory diagnostic +workshop. Captures capability scores across 12 competencies, ingests +client operational baseline, computes value-at-stake bounded by +capability gaps, exports structured data. + +**Users:** Single facilitator (Robert) running a live half-day workshop +with 4–8 client participants. + +**NOT for:** Client self-service, unattended use, public deployment, SaaS. + +## 1. Stack + +Python 3.11+, Jupyter Notebook, Mercury (mljar-mercury), pandas, plotly +(matplotlib fallback), pydantic, PyYAML. Runs locally. No server, no +auth, no database. + +## 2. Structure + +Study package (`diaglib/`) with models / scoring / value_math / visuals / +export; `configs/` (base + industry overlays); one deliverable notebook; +gitignored `exports/`. + +## 3. Data model + +`Engagement` (id `client_slug_YYYY-MM-DD`, client, industry config, +facilitator, date, participants, baseline, scores, computed value, +notes) · `Participant` (name, role, function cx|it|ops|finance|other) · +`OperationalBaseline` (annual_contact_volume, blended_cost_per_contact, +agent_headcount, annual_attrition_rate, current_containment_rate, +average_handle_time_seconds; optional csat_baseline, revenue_at_risk; +per-field confidence known|estimated|unknown) · `CompetencyScore` +(competency, dimension, score 1–5, evidence line, scorer role, +timestamp) · `ValueAtStake` (theoretical annual low/high, realizable +18-mo low/high, trapped low/high, binding constraints, unlock sequence) +· `UnlockMove` (competencies, level lift, cost range, weeks, value +unlocked range). + +## 4. Configs + +**base.yaml** — 12 competencies across 4 dimensions, each with +description, failure vignette, level descriptors 1–5; capping heuristic +(weakest foundational score → realization band): 1: 0.00–0.15, +2: 0.25–0.40, 3: 0.50–0.65, 4: 0.65–0.85, 5: 0.80–1.00; foundational +competencies: process_discovery, data_readiness, technical_architecture. + +**contact_center.yaml** — value drivers: deflection/containment lift +(+15–35 pts × volume × cost/contact), AHT reduction (15–25%), attrition +reduction (10–20%, $15K/replacement default); unlock costs per +level-lift per foundational competency (sparse OK). + +**financial_services.yaml** — stub for MVP. + +## 5. Notebook sections + +0 Setup (hidden) · 1 Engagement form · 2 Operational baseline with +confidence flags · 3 Capability scoring, one screen per competency +(name, description, vignette, level descriptors; score + evidence) · +4 Live analysis · 5 Visuals (heatmap, value bands, trapped/realizable +split, unlock chart) · 6 Export button → JSON + CSV. + +## 6. Value math + +theoretical = Σ driver ranges → realization band from weakest +foundational score → realizable_18mo = theoretical × factor × 1.5 → +trapped = theoretical − realizable run-rate → binding constraints = all +foundational competencies at the weakest score → unlock sequence: lift +binding constraints one level, recompute factor, up to 3 moves. + +Guard rails: all outputs are ranges; explicit warnings on 🔴-unknown +inputs; money display ≤ 2 significant figures. + +## 7–8. Visuals & exports + +Room-facing interactive plotly. Heatmap 4×3 with scores + evidence +hover; horizontal value bands (theoretical light / realizable dark, +trapped labeled); split chart; unlock cost-vs-value chart. +`exports/{engagement_id}.json` (full Engagement — source of truth) + +`.csv` (one row per competency: engagement_id, client_name, industry, +workshop_date, competency_id, dimension, score, evidence, +is_foundational, is_binding_constraint). + +## 9. Non-goals (MVP) + +No auth · no multi-stakeholder independent scoring (v1.1) · no LLM +recommendations · no PDF · no history dashboard · no cloud · no SaaS · +no client-facing scoring. + +## 10. Acceptance + +Launch Mercury → contact_center → new engagement; enter client info + +4–8 participants; six baseline numbers with confidence flags; score all +12 competencies with evidence; four visuals render live; Export writes +valid JSON + CSV; (nice-to-have) reload saved JSON; edit YAML ranges → +recomputed outputs. Done = end-to-end in under 90 minutes with mock +inputs and sensible output. + +## 12. Open questions (Robert) + +- Benchmark citations for §4 ranges before first real client (Alan's + research subagent offer pending go-ahead). +- $15K cost-per-replacement default — config-driven, tune per engagement. +- Multi-stakeholder scoring — v1.1 if workshops routinely score + independently; don't build now. diff --git a/studies/202607_CX_AI_Diagnostic/exports/.gitkeep b/studies/202607_CX_AI_Diagnostic/exports/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/studies/202607_CX_AI_Diagnostic/notebooks/diagnostic.ipynb b/studies/202607_CX_AI_Diagnostic/notebooks/diagnostic.ipynb new file mode 100644 index 0000000..3e5a253 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/notebooks/diagnostic.ipynb @@ -0,0 +1,10520 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a3634d16", + "metadata": {}, + "source": [ + "# CX AI Advisory Diagnostic\n", + "\n", + "The facilitator's cockpit for the CX AI Advisory diagnostic workshop:\n", + "capture capability scores across **12 competencies** in four dimensions,\n", + "ingest the client's operational baseline, and watch the **value-at-stake\n", + "analysis** — bounded by the capability gaps — recompute live in the room.\n", + "\n", + "**This notebook is the deliverable.** Serve it with\n", + "`mercury --working-dir .` from the study root and share the screen. Work\n", + "the sidebar top-to-bottom: engagement, baseline, then one competency at a\n", + "time. The stage shows the current competency's card, the heatmap, the\n", + "value analysis, and the unlock sequence. Click **Export JSON + CSV** at\n", + "the bottom to write the structured engagement record to `exports/`.\n", + "\n", + "All content and math live in `diaglib/` and `configs/*.yaml` — the\n", + "notebook only arranges and renders them. Outputs are **ranges, never\n", + "point estimates**, and money displays at two significant figures.\n", + "\n", + "Confidence legend: 🟢 known · 🟡 estimated · 🔴 unknown — flag each\n", + "baseline input; unknowns surface as explicit warnings in the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "8196c6ba", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:37.330585Z", + "iopub.status.busy": "2026-07-19T23:45:37.330333Z", + "iopub.status.idle": "2026-07-19T23:45:37.878564Z", + "shell.execute_reply": "2026-07-19T23:45:37.877675Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "diaglib loaded — 12 competencies · industries: contact_center, financial_services\n" + ] + } + ], + "source": [ + "# ── Setup ──────────────────────────────────────────────────────────\n", + "import sys, pathlib\n", + "_ROOT = pathlib.Path.cwd()\n", + "if not (_ROOT / \"diaglib\").exists(): # notebook lives in notebooks/\n", + " _ROOT = _ROOT.parent\n", + "sys.path.insert(0, str(_ROOT))\n", + "\n", + "import datetime as dt\n", + "import html as _html\n", + "\n", + "import mercury as mr\n", + "import pandas as pd\n", + "from IPython.display import display\n", + "\n", + "# Single source of truth — all math and content live in the library;\n", + "# only presentation (and Mercury widgets) lives here.\n", + "from diaglib import (\n", + " BASELINE_FIELDS, CONFIDENCE_ICON, CSV_COLUMNS,\n", + " OperationalBaseline, backstage, build_engagement, build_scores,\n", + " configs_dir, dimension_rollup, engagement_json, evidence_coverage,\n", + " heatmap_fig, heatmap_grid, list_industries, load_config, money,\n", + " parse_participants, scores_dataframe, split_fig, unlock_fig,\n", + " value_at_stake, value_bands_fig, write_exports,\n", + ")\n", + "\n", + "pd.options.display.float_format = \"{:,.0f}\".format\n", + "\n", + "CONFIGS_DIR = configs_dir(_ROOT)\n", + "EXPORTS_DIR = _ROOT / \"exports\"\n", + "INDUSTRIES = list_industries(CONFIGS_DIR)\n", + "# The competency model is industry-independent (overlays may not redefine\n", + "# it — the loader enforces that), so widgets can build from any config.\n", + "_BASE = load_config(\"contact_center\", CONFIGS_DIR)\n", + "COMPETENCIES = _BASE.competencies\n", + "DIMENSION_NAME = {d.id: d.name for d in _BASE.dimensions}\n", + "\n", + "# ── Brand palette (docs/brand.md, light theme) ─────────────────────\n", + "NAVY, INK, MUTED = \"#151d2c\", \"#2e404d\", \"#586671\"\n", + "BLUE, GREEN, LINE = \"#0072bc\", \"#00a34c\", \"#e2e6e9\"\n", + "CARD_BG, HAIRLINE, HILITE = \"#f8f8f8\", \"#d5d9db\", \"#dcecfa\"\n", + "FONT = \"Georgia, 'Times New Roman', serif\"\n", + "BODY_FONT = \"Arial, 'Helvetica Neue', Helvetica, sans-serif\"\n", + "\n", + "\n", + "def esc(s):\n", + " return _html.escape(str(s))\n", + "\n", + "\n", + "# ── Workshop seeds — the gate's mock scenario; overwrite live ──────\n", + "# Headless nbconvert renders every widget at its seed, so the seeds form\n", + "# a coherent, gate-passing scenario (Pattern §3).\n", + "SEED_CLIENT = \"Acme Demo Co\"\n", + "SEED_DATE = \"2026-07-19\"\n", + "SEED_FACILITATOR = \"Robert Helewka\"\n", + "SEED_PARTICIPANTS = (\"Jane Example | VP Customer Experience | cx; \"\n", + " \"Sam Sample | Contact Center Ops Director | ops\")\n", + "SEED_BASELINE = {\n", + " \"annual_contact_volume\": 1_200_000,\n", + " \"blended_cost_per_contact\": 6.50,\n", + " \"agent_headcount\": 450,\n", + " \"annual_attrition_rate\": 0.30,\n", + " \"current_containment_rate\": 0.20,\n", + " \"average_handle_time_seconds\": 420,\n", + "}\n", + "CONFIDENCE_CHOICES = [\"🟢 known\", \"🟡 estimated\", \"🔴 unknown\"]\n", + "SEED_CONFIDENCE = {\n", + " \"annual_contact_volume\": \"🟢 known\",\n", + " \"blended_cost_per_contact\": \"🟡 estimated\",\n", + " \"agent_headcount\": \"🟢 known\",\n", + " \"annual_attrition_rate\": \"🟡 estimated\",\n", + " \"current_containment_rate\": \"🟡 estimated\",\n", + " \"average_handle_time_seconds\": \"🟢 known\",\n", + "}\n", + "# Seed capability profile: data_readiness is the unique weakest\n", + "# foundation, so the demo shows a single binding constraint.\n", + "SEED_SCORES = {\n", + " \"automation_ai_strategy\": (2, \"AI driven by board pressure; no written thesis\"),\n", + " \"value_realization\": (2, \"Business cases pre-investment only\"),\n", + " \"executive_alignment\": (3, \"COO owns CX AI; steering meets quarterly\"),\n", + " \"process_discovery\": (3, \"Top 10 call reasons mapped with volumes\"),\n", + " \"data_readiness\": (2, \"KB stale; interaction data siloed in recordings\"),\n", + " \"technical_architecture\": (3, \"CCaaS APIs available; shared integration layer WIP\"),\n", + " \"use_case_prioritization\": (3, \"Scored backlog reviewed monthly\"),\n", + " \"delivery_capability\": (3, \"Two bots in production via SI partner\"),\n", + " \"talent_and_skills\": (2, \"One conversation designer, contractor\"),\n", + " \"ai_operations\": (2, \"Containment eyeballed weekly, no drift alerts\"),\n", + " \"change_adoption\": (3, \"Agent champions for copilot rollout\"),\n", + " \"governance_and_risk\": (3, \"AI policy signed; review board for voice bots\"),\n", + "}\n", + "# label, min, max, step per baseline field (explicit min/max — Pattern §3).\n", + "BASELINE_META = {\n", + " \"annual_contact_volume\": (\"Annual contact volume\", 0, 100_000_000, 10_000),\n", + " \"blended_cost_per_contact\": (\"Blended cost per contact ($)\", 0, 100, 0.25),\n", + " \"agent_headcount\": (\"Agent headcount\", 0, 100_000, 10),\n", + " \"annual_attrition_rate\": (\"Annual attrition rate (0-1)\", 0, 1, 0.01),\n", + " \"current_containment_rate\": (\"Current containment rate (0-1)\", 0, 1, 0.01),\n", + " \"average_handle_time_seconds\": (\"Average handle time (seconds)\", 0, 3600, 10),\n", + "}\n", + "\n", + "backstage(f\"diaglib loaded — {len(COMPETENCIES)} competencies · \"\n", + " f\"industries: {', '.join(INDUSTRIES)}\")" + ] + }, + { + "cell_type": "markdown", + "id": "bbfd8baf", + "metadata": {}, + "source": [ + "## How to run this session\n", + "\n", + "- **Sidebar §1 — Engagement.** Client, industry config, date, participants\n", + " (`Name | Role | Function` separated by `;` — functions: cx, it, ops,\n", + " finance, other), and a running notes box.\n", + "- **Sidebar §2 — Operational baseline.** Six numbers. If unknown, best\n", + " estimate is fine — set the confidence flag and the analysis will carry\n", + " the uncertainty explicitly.\n", + "- **Sidebar §3 — Capability scoring.** Pick **Now scoring**, read the\n", + " competency card on stage with the room, set the 1–5 slider, capture one\n", + " line of evidence, move to the next. The heatmap and value analysis\n", + " update live as you go.\n", + "- **Export.** The button at the bottom of the page writes\n", + " `exports/{engagement_id}.json` (source of truth) and `.csv` (flat\n", + " scores) — a deliberate snapshot at click time.\n", + "- **Backstage** (JupyterLab / nbconvert) — the verification gate and the\n", + " machine-readable appendix; neither shows on the Mercury stage." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "6393a965", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:37.880508Z", + "iopub.status.busy": "2026-07-19T23:45:37.880214Z", + "iopub.status.idle": "2026-07-19T23:45:37.904951Z", + "shell.execute_reply": "2026-07-19T23:45:37.904267Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "5feaf4858ee043a8b09f3507ce84f49c", + "position": "sidebar", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "5feaf4858ee043a8b09f3507ce84f49c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "bae59fd8c40a4e16bde1f847d17c7192", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "bae59fd8c40a4e16bde1f847d17c7192", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "2782d2713dfc449aaa69d11007cace4e", + "position": "sidebar", + "widget": "DateInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "2782d2713dfc449aaa69d11007cace4e", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "955923ab919f4bce897169977d539ea5", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "955923ab919f4bce897169977d539ea5", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "d34dbe00c35d4eb6b8a7da2340dbe2e1", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "d34dbe00c35d4eb6b8a7da2340dbe2e1", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "2ef89a29c65c4d978ec5ced9504dba73", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "2ef89a29c65c4d978ec5ced9504dba73", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── 1 · Engagement setup (sidebar — widgets ONLY, no other output) ──\n", + "# Mercury re-runs only cells BELOW a changed widget: every .value is\n", + "# read in the state cell further down, never here (Pattern §3).\n", + "mr.Markdown(\"#### 1 · Engagement\", position=\"sidebar\")\n", + "_client_w = mr.TextInput(label=\"Client name\", value=SEED_CLIENT)\n", + "_industry_w = mr.Select(label=\"Industry config\", value=\"contact_center\",\n", + " choices=INDUSTRIES)\n", + "_date_w = mr.DateInput(label=\"Workshop date\", value=SEED_DATE)\n", + "_facilitator_w = mr.TextInput(label=\"Facilitator\", value=SEED_FACILITATOR)\n", + "_participants_w = mr.TextInput(\n", + " label=\"Participants — Name | Role | Function; ...\",\n", + " value=SEED_PARTICIPANTS)\n", + "_notes_w = mr.TextInput(label=\"Session notes\", value=\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "519ceb51", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:37.906389Z", + "iopub.status.busy": "2026-07-19T23:45:37.906260Z", + "iopub.status.idle": "2026-07-19T23:45:37.943107Z", + "shell.execute_reply": "2026-07-19T23:45:37.941718Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "0384abc193994b69881674157eb6b28f", + "position": "sidebar", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "0384abc193994b69881674157eb6b28f", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "d59db85587a8467dae0addb485bc3cbc", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "d59db85587a8467dae0addb485bc3cbc", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "878ac4372b24422d9e06d9c6a77ed9b2", + "position": "sidebar", + "widget": "NumberInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "878ac4372b24422d9e06d9c6a77ed9b2", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "956c843fdb3847f6a6e9e8f07824acb9", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "956c843fdb3847f6a6e9e8f07824acb9", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "facdfdd6c0494307b51225d81b78aad8", + "position": "sidebar", + "widget": "NumberInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "facdfdd6c0494307b51225d81b78aad8", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "9c7d24f3d7b64b3e858baaa83002d48d", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "9c7d24f3d7b64b3e858baaa83002d48d", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "8843aabb37b748a78228f4b18c49e6aa", + "position": "sidebar", + "widget": "NumberInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "8843aabb37b748a78228f4b18c49e6aa", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "ec1d09aab4cd43d7821005f37d7acd59", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "ec1d09aab4cd43d7821005f37d7acd59", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "90d4dc2d15514ebda566e852ce78bf73", + "position": "sidebar", + "widget": "NumberInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "90d4dc2d15514ebda566e852ce78bf73", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "c82b1adbfcd44ff88abd892f4fd78301", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "c82b1adbfcd44ff88abd892f4fd78301", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "60fabcff9f5e4a37942bb364eccddb85", + "position": "sidebar", + "widget": "NumberInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "60fabcff9f5e4a37942bb364eccddb85", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "780c3efc5ec54ecc9ea40ce81f52cc28", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "780c3efc5ec54ecc9ea40ce81f52cc28", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── 2 · Operational baseline (sidebar — widgets ONLY) ───────────────\n", + "# Six numbers + a confidence flag each. Explicit min/max on every\n", + "# NumberInput — Mercury clamps out-of-range seeds to a default range.\n", + "mr.Markdown(\"#### 2 · Operational baseline\", position=\"sidebar\")\n", + "_baseline_w, _conf_w = {}, {}\n", + "for _f in BASELINE_FIELDS:\n", + " _label, _min, _max, _step = BASELINE_META[_f]\n", + " _baseline_w[_f] = mr.NumberInput(label=_label, value=SEED_BASELINE[_f],\n", + " min=_min, max=_max, step=_step)\n", + " _conf_w[_f] = mr.Select(label=f\"{_label} — confidence\",\n", + " value=SEED_CONFIDENCE[_f],\n", + " choices=CONFIDENCE_CHOICES)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "53450686", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:37.944822Z", + "iopub.status.busy": "2026-07-19T23:45:37.944677Z", + "iopub.status.idle": "2026-07-19T23:45:38.038687Z", + "shell.execute_reply": "2026-07-19T23:45:38.037711Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "4bbea152c5354344bad9cae9ae4b131f", + "position": "sidebar", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "4bbea152c5354344bad9cae9ae4b131f", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "9ede9faa5bc44112a30d3093c7709cbc", + "position": "sidebar", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "9ede9faa5bc44112a30d3093c7709cbc", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "eecaf52a0a074f02a04efd099b4f22d9", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "eecaf52a0a074f02a04efd099b4f22d9", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "d48a2c7bbda8440aa87e9078553f38e9", + "position": "sidebar", + "widget": "SliderWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "d48a2c7bbda8440aa87e9078553f38e9", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "1dd77bf8ef284086a98c3f506dac122d", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "1dd77bf8ef284086a98c3f506dac122d", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "738b9403a2cb4d3498f2e174430c6d5b", + "position": "sidebar", + "widget": "SliderWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "738b9403a2cb4d3498f2e174430c6d5b", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "bdf928b007aa4132aefb644a6b6c751b", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "bdf928b007aa4132aefb644a6b6c751b", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "114ea157213646ccba3e4a6ea52c2856", + "position": "sidebar", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "114ea157213646ccba3e4a6ea52c2856", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "96a1888c76f24e1ebc7f86c991ada96e", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "96a1888c76f24e1ebc7f86c991ada96e", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "5cc39b1eef054bc9a484708bbcf282ee", + "position": "sidebar", + "widget": "SliderWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "5cc39b1eef054bc9a484708bbcf282ee", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "c0def29eb51e47f78e0c2bd3db3afc0a", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "c0def29eb51e47f78e0c2bd3db3afc0a", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "741f4d5aeaf34ea6bebbba0b72f23426", + "position": "sidebar", + "widget": "SliderWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "741f4d5aeaf34ea6bebbba0b72f23426", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "f0ead6ff95fd46d598e4b8cd15cce31d", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "f0ead6ff95fd46d598e4b8cd15cce31d", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "a7000c769e234457a69473437aea7491", + "position": "sidebar", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "a7000c769e234457a69473437aea7491", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "82b3e6f7ce29429b94f0beb47b226b59", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "82b3e6f7ce29429b94f0beb47b226b59", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "36927983549046499f7d080a20c1b0b8", + "position": "sidebar", + "widget": "SliderWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "36927983549046499f7d080a20c1b0b8", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "e91abb56e78a484598c5d47806b26282", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "e91abb56e78a484598c5d47806b26282", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "7aa2b22ed12d4c1a9ff00e2432464da8", + "position": "sidebar", + "widget": "SliderWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "7aa2b22ed12d4c1a9ff00e2432464da8", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "8bb4e603517a49d7a9976ee555dff224", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "8bb4e603517a49d7a9976ee555dff224", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "333656890d3a4dce8a18171604757325", + "position": "sidebar", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "333656890d3a4dce8a18171604757325", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "33c48116b82842f8b1a571804a90ebca", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "33c48116b82842f8b1a571804a90ebca", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "275ca35bfb974e3bab5d507f521fc4c2", + "position": "sidebar", + "widget": "SliderWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "275ca35bfb974e3bab5d507f521fc4c2", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "40697a7b3df442ffb315149b61aaa646", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "40697a7b3df442ffb315149b61aaa646", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "74ca96bfbd7a44c7a87eb3c1e0a895e0", + "position": "sidebar", + "widget": "SliderWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "74ca96bfbd7a44c7a87eb3c1e0a895e0", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "d7940b33fc6f484582428064dfc25d0d", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "d7940b33fc6f484582428064dfc25d0d", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── 3 · Capability scoring (sidebar — widgets ONLY) ─────────────────\n", + "# One screen per competency on stage: pick \"Now scoring\", read the card\n", + "# with the room, set the slider, capture one line of evidence. Labels\n", + "# are distinct per widget so Mercury's cache never collides.\n", + "mr.Markdown(\"#### 3 · Capability scoring\", position=\"sidebar\")\n", + "_now_scoring_w = mr.Select(\n", + " label=\"Now scoring\",\n", + " value=f\"1 · {COMPETENCIES[0].name}\",\n", + " choices=[f\"{_i + 1} · {_c.name}\" for _i, _c in enumerate(COMPETENCIES)])\n", + "_score_w, _evidence_w = {}, {}\n", + "_prev_dim = None\n", + "for _c in COMPETENCIES:\n", + " if _c.dimension != _prev_dim:\n", + " mr.Markdown(f\"**{DIMENSION_NAME[_c.dimension]}**\", position=\"sidebar\")\n", + " _prev_dim = _c.dimension\n", + " _score_w[_c.id] = mr.Slider(label=f\"Score — {_c.name}\",\n", + " min=1, max=5, value=SEED_SCORES[_c.id][0])\n", + " _evidence_w[_c.id] = mr.TextInput(label=f\"Evidence — {_c.name}\",\n", + " value=SEED_SCORES[_c.id][1])" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "5e127edd", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:38.040813Z", + "iopub.status.busy": "2026-07-19T23:45:38.040663Z", + "iopub.status.idle": "2026-07-19T23:45:38.066837Z", + "shell.execute_reply": "2026-07-19T23:45:38.066033Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Value at stake: $2.5M-$5.1M theoretical per year · $950K-$3.1M realizable over 18 months — capped at level 2 by Data Readiness\n", + "engagement acme_demo_co_2026-07-19 · 2 participants · evidence 12/12\n" + ] + } + ], + "source": [ + "# ── Session state (re-runs on any sidebar change) ───────────────────\n", + "# Read every widget .value; all computation happens in diaglib.\n", + "CLIENT_NAME = str(_client_w.value).strip() or SEED_CLIENT\n", + "INDUSTRY = str(_industry_w.value)\n", + "CONFIG = load_config(INDUSTRY, CONFIGS_DIR)\n", + "WORKSHOP_DATE = dt.date.fromisoformat(str(_date_w.value) or SEED_DATE)\n", + "PARTICIPANTS = parse_participants(str(_participants_w.value))\n", + "NOTES = str(_notes_w.value)\n", + "\n", + "_vals = {f: float(_baseline_w[f].value) for f in BASELINE_FIELDS}\n", + "BASELINE = OperationalBaseline(\n", + " annual_contact_volume=int(_vals[\"annual_contact_volume\"]),\n", + " blended_cost_per_contact=_vals[\"blended_cost_per_contact\"],\n", + " agent_headcount=int(_vals[\"agent_headcount\"]),\n", + " annual_attrition_rate=_vals[\"annual_attrition_rate\"],\n", + " current_containment_rate=_vals[\"current_containment_rate\"],\n", + " average_handle_time_seconds=int(_vals[\"average_handle_time_seconds\"]),\n", + " field_confidence={f: str(_conf_w[f].value).split()[-1]\n", + " for f in BASELINE_FIELDS},\n", + ")\n", + "\n", + "RAW_SCORES = {c.id: (int(_score_w[c.id].value), str(_evidence_w[c.id].value))\n", + " for c in COMPETENCIES}\n", + "SCORES = build_scores(CONFIG, RAW_SCORES, scored_at=dt.datetime.now())\n", + "VAS = value_at_stake(CONFIG, BASELINE, SCORES)\n", + "ENGAGEMENT = build_engagement(\n", + " config=CONFIG, client_name=CLIENT_NAME,\n", + " facilitator=str(_facilitator_w.value), workshop_date=WORKSHOP_DATE,\n", + " participants=PARTICIPANTS, baseline=BASELINE, scores=SCORES,\n", + " computed_value=VAS, notes=NOTES)\n", + "\n", + "NOW_SCORING = COMPETENCIES[int(str(_now_scoring_w.value).split(\" · \")[0]) - 1]\n", + "_done, _total = evidence_coverage(SCORES)\n", + "\n", + "# One curated line on stage; warnings surface for the room; echo backstage.\n", + "if CONFIG.value_drivers:\n", + " _bind = \", \".join(CONFIG.competency(c).name for c in VAS.binding_constraints)\n", + " print(f\"Value at stake: {money(VAS.theoretical_annual_value_low)}-\"\n", + " f\"{money(VAS.theoretical_annual_value_high)} theoretical per year · \"\n", + " f\"{money(VAS.realizable_18mo_low)}-{money(VAS.realizable_18mo_high)} \"\n", + " f\"realizable over 18 months — capped at level \"\n", + " f\"{VAS.weakest_foundational_score} by {_bind}\")\n", + "for _warning in VAS.warnings:\n", + " print(f\"⚠ {_warning}\")\n", + "backstage(f\"engagement {ENGAGEMENT.engagement_id} · \"\n", + " f\"{len(PARTICIPANTS)} participants · evidence {_done}/{_total}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "5c3959a5", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:38.069170Z", + "iopub.status.busy": "2026-07-19T23:45:38.068934Z", + "iopub.status.idle": "2026-07-19T23:45:38.082309Z", + "shell.execute_reply": "2026-07-19T23:45:38.081608Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "a76214e4ed5548de8e248286ea47d040", + "position": "inline", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "a76214e4ed5548de8e248286ea47d040", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
{esc(p.name)}'\n", + " + (f\" · {esc(p.role)}\" if p.role else \"\")\n", + " + f' {esc(p.function)}'\n", + " for p in PARTICIPANTS) or (\n", + " f''\n", + " f'no participants captured yet')\n", + "\n", + "_rows = \"\"\n", + "for _f in BASELINE_FIELDS:\n", + " _v = getattr(BASELINE, _f)\n", + " _shown = f\"{_v:,.2f}\" if isinstance(_v, float) and _v < 10 else f\"{_v:,.0f}\"\n", + " _rows += (\n", + " f'{BASELINE_META[_f][0]}'\n", + " f'{_shown}'\n", + " f'{CONFIDENCE_ICON[BASELINE.confidence_for(_f)]}'\n", + " f'')\n", + "\n", + "_ = mr.Markdown(text=(\n", + " f'
'\n", + " f'
'\n", + " f'{esc(CLIENT_NAME)} — CX AI Diagnostic
'\n", + " f'
'\n", + " f'{esc(CONFIG.display_name)} · {WORKSHOP_DATE.isoformat()} · '\n", + " f'facilitated by {esc(ENGAGEMENT.facilitator)} · '\n", + " f'evidence captured {_done}/{_total}
'\n", + " f'
{_chips}
'\n", + " f'
'\n", + " f'
'\n", + " f'Operational baseline
'\n", + " f'{_rows}
'))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "0807c87c", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:38.084220Z", + "iopub.status.busy": "2026-07-19T23:45:38.084075Z", + "iopub.status.idle": "2026-07-19T23:45:38.097120Z", + "shell.execute_reply": "2026-07-19T23:45:38.094011Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "a57e5835f51a4a0ea099d86287ba82bf", + "position": "inline", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "a57e5835f51a4a0ea099d86287ba82bf", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
{_s}')\n", + "\n", + "_levels = \"\"\n", + "for _lvl in range(1, 6):\n", + " _sel = _lvl == _score\n", + " _levels += (\n", + " f'{_lvl}'\n", + " f''\n", + " f'{esc(_c.level_descriptors[_lvl])}')\n", + "\n", + "_evidence_html = (\n", + " f' {esc(_evidence)}' if _evidence\n", + " else f'no evidence captured yet — '\n", + " f'one line: what makes this a level {_score}?')\n", + "\n", + "_ = mr.Markdown(text=(\n", + " f'
'\n", + " f'
{_boxes}
'\n", + " f'
'\n", + " f'
'\n", + " f'{DIMENSION_NAME[_c.dimension]}
'\n", + " f'
'\n", + " f'{esc(_c.name)}
'\n", + " f'
'\n", + " f'{esc(_c.description)}
'\n", + " f'
'\n", + " f'\"{esc(_c.failure_vignette)}\"
'\n", + " f'{_levels}
'\n", + " f'
'\n", + " f'Evidence: {_evidence_html}
'\n", + " f'
'))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "fd7ee43b", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:38.099790Z", + "iopub.status.busy": "2026-07-19T23:45:38.099524Z", + "iopub.status.idle": "2026-07-19T23:45:39.732315Z", + "shell.execute_reply": "2026-07-19T23:45:39.729895Z" + } + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "colorscale": [ + [ + 0.0, + "#ef8a76" + ], + [ + 0.5, + "#f0efe9" + ], + [ + 1.0, + "#57c993" + ] + ], + "customdata": [ + [ + "Automation & AI Strategy — level 2
Aspirational vision, no operating model implications defined.
AI driven by board pressure; no written thesis", + "Value Realization — level 2
Business cases exist pre-investment; nobody measures after go-live.
Business cases pre-investment only", + "Executive Alignment — level 3
Named executive owner; cross-functional steering exists on paper.
COO owns CX AI; steering meets quarterly" + ], + [ + "Process Discovery — level 3
Priority journeys mapped at task level with volumes and handle data.
Top 10 call reasons mapped with volumes", + "Data Readiness — level 2
Key sources identified; access is manual and quality unknown.
KB stale; interaction data siloed in recordings", + "Technical Architecture — level 3
Reference architecture defined; shared integration layer for priority systems.
CCaaS APIs available; shared integration layer WIP" + ], + [ + "Use Case Prioritization — level 3
Value and feasibility scoring; a prioritized backlog is reviewed.
Scored backlog reviewed monthly", + "Delivery Capability — level 3
A standard delivery path exists; a few use cases run in production.
Two bots in production via SI partner", + "Talent & Skills — level 2
Isolated enthusiasts self-teach; no roles or paths defined.
One conversation designer, contractor" + ], + [ + "AI Operations — level 2
Manual spot checks; tuning happens when someone escalates.
Containment eyeballed weekly, no drift alerts", + "Change & Adoption — level 3
Structured change program for major rollouts; adoption tracked.
Agent champions for copilot rollout", + "Governance & Risk — level 3
AI policy and a review board for high-risk use cases.
AI policy signed; review board for voice bots" + ] + ], + "hovertemplate": "%{customdata}", + "showscale": false, + "text": [ + [ + "2
Automation & AI Strategy", + "2
Value Realization", + "3
Executive Alignment" + ], + [ + "3
Process Discovery", + "2
Data Readiness", + "3
Technical Architecture" + ], + [ + "3
Use Case Prioritization", + "3
Delivery Capability", + "2
Talent & Skills" + ], + [ + "2
AI Operations", + "3
Change & Adoption", + "3
Governance & Risk" + ] + ], + "textfont": { + "color": "#0b0b0b", + "size": 13 + }, + "texttemplate": "%{text}", + "type": "heatmap", + "x": [ + 0, + 1, + 2 + ], + "xgap": 3, + "y": [ + "Strategy & Value", + "Foundations", + "Delivery", + "Sustain" + ], + "ygap": 3, + "z": [ + [ + 2, + 2, + 3 + ], + [ + 3, + 2, + 3 + ], + [ + 3, + 3, + 2 + ], + [ + 2, + 3, + 3 + ] + ], + "zmax": 5, + "zmin": 1 + } + ], + "layout": { + "font": { + "color": "#52514e", + "family": "system-ui, -apple-system, \"Segoe UI\", sans-serif", + "size": 13 + }, + "height": 480, + "legend": { + "font": { + "color": "#52514e", + "size": 11 + }, + "orientation": "h", + "x": 0, + "y": -0.12, + "yanchor": "top" + }, + "margin": { + "b": 60, + "l": 70, + "r": 30, + "t": 70 + }, + "paper_bgcolor": "#fcfcfb", + "plot_bgcolor": "#fcfcfb", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "font": { + "color": "#0b0b0b", + "size": 16 + }, + "text": "Capability heatmap
12 competencies, levels 1–5 · hover a cell for the evidence", + "x": 0.02, + "xanchor": "left" + }, + "xaxis": { + "visible": false + }, + "yaxis": { + "autorange": "reversed", + "showgrid": false, + "tickfont": { + "color": "#52514e", + "size": 13 + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "base": [ + 2542500.0 + ], + "hovertemplate": "Theoretical value (annual): $2.5M – $5.1M", + "marker": { + "color": "#9ec5f4", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "orientation": "h", + "showlegend": false, + "type": "bar", + "x": [ + 2542500.0 + ], + "y": [ + "Theoretical value (annual)" + ] + }, + { + "base": [ + 953437.5 + ], + "hovertemplate": "Realizable over 18 months: $950K – $3.1M", + "marker": { + "color": "#2a78d6", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "orientation": "h", + "showlegend": false, + "type": "bar", + "x": [ + 2097562.5 + ], + "y": [ + "Realizable over 18 months" + ] + } + ], + "layout": { + "annotations": [ + { + "font": { + "color": "#0b0b0b", + "size": 12 + }, + "showarrow": false, + "text": "$2.5M – $5.1M", + "x": 5085000.0, + "xanchor": "left", + "xshift": 6, + "y": "Theoretical value (annual)" + }, + { + "font": { + "color": "#0b0b0b", + "size": 12 + }, + "showarrow": false, + "text": "$950K – $3.1M", + "x": 3051000.0, + "xanchor": "left", + "xshift": 6, + "y": "Realizable over 18 months" + }, + { + "align": "left", + "font": { + "color": "#0b0b0b", + "size": 13 + }, + "showarrow": false, + "text": "Trapped by the capability gap: $1.5M – $3.8M per year", + "x": 0.02, + "xanchor": "left", + "xref": "paper", + "y": -0.32, + "yref": "paper" + } + ], + "bargap": 0.5, + "font": { + "color": "#52514e", + "family": "system-ui, -apple-system, \"Segoe UI\", sans-serif", + "size": 13 + }, + "height": 300, + "legend": { + "font": { + "color": "#52514e", + "size": 11 + }, + "orientation": "h", + "x": 0, + "y": -0.12, + "yanchor": "top" + }, + "margin": { + "b": 90, + "l": 70, + "r": 30, + "t": 70 + }, + "paper_bgcolor": "#fcfcfb", + "plot_bgcolor": "#fcfcfb", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "font": { + "color": "#0b0b0b", + "size": 16 + }, + "text": "Value at stake
ranges, never points · realization capped by the weakest foundation", + "x": 0.02, + "xanchor": "left" + }, + "xaxis": { + "gridcolor": "#e1e0d9", + "rangemode": "tozero", + "tickfont": { + "color": "#898781" + }, + "tickformat": "$~s", + "zeroline": false + }, + "yaxis": { + "autorange": "reversed", + "showgrid": false, + "tickfont": { + "color": "#52514e", + "size": 13 + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "Realizable: %{x:$,.0f}%{y}", + "insidetextfont": { + "color": "#ffffff" + }, + "marker": { + "color": "#2a78d6", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Realizable (annual run-rate)", + "orientation": "h", + "text": [ + "$640K", + "$2.0M" + ], + "textposition": "inside", + "type": "bar", + "x": [ + 635625.0, + 2034000.0 + ], + "y": [ + "Conservative", + "Optimistic" + ] + }, + { + "hovertemplate": "Trapped: %{x:$,.0f}%{y}", + "insidetextfont": { + "color": "#0b0b0b" + }, + "marker": { + "color": "#eda100", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Trapped by capability gap", + "orientation": "h", + "text": [ + "$1.9M", + "$3.1M" + ], + "textposition": "inside", + "type": "bar", + "x": [ + 1906875.0, + 3051000.0 + ], + "y": [ + "Conservative", + "Optimistic" + ] + } + ], + "layout": { + "bargap": 0.5, + "barmode": "stack", + "font": { + "color": "#52514e", + "family": "system-ui, -apple-system, \"Segoe UI\", sans-serif", + "size": 13 + }, + "height": 300, + "legend": { + "font": { + "color": "#52514e", + "size": 11 + }, + "orientation": "h", + "traceorder": "normal", + "x": 0, + "y": -0.12, + "yanchor": "top" + }, + "margin": { + "b": 60, + "l": 70, + "r": 30, + "t": 70 + }, + "paper_bgcolor": "#fcfcfb", + "plot_bgcolor": "#fcfcfb", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "font": { + "color": "#0b0b0b", + "size": 16 + }, + "text": "Where the annual value goes
each scenario splits its own theoretical total", + "x": 0.02, + "xanchor": "left" + }, + "xaxis": { + "gridcolor": "#e1e0d9", + "tickfont": { + "color": "#898781" + }, + "tickformat": "$~s", + "zeroline": false + }, + "yaxis": { + "autorange": "reversed", + "showgrid": false, + "tickfont": { + "color": "#52514e", + "size": 13 + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "base": [ + 300000.0, + 800000.0, + 1050000.0 + ], + "customdata": [ + [ + "Data Readiness", + "$300K – $600K" + ], + [ + "Process Discovery + Data Readiness + Technical Architecture", + "$800K – $1.6M" + ], + [ + "Process Discovery + Data Readiness + Technical Architecture", + "$1.0M – $2.1M" + ] + ], + "hovertemplate": "%{customdata[0]}
Investment: %{customdata[1]}", + "marker": { + "color": "#e34948", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Investment (range)", + "type": "bar", + "x": [ + "1 · Data Readiness
level 2 → 3", + "2 · joint lift ×3
level 3 → 4", + "3 · joint lift ×3
level 4 → 5" + ], + "y": [ + 300000.0, + 800000.0, + 1050000.0 + ] + }, + { + "base": [ + 635625.0, + 381375.00000000006, + 381375.00000000006 + ], + "customdata": [ + [ + "Data Readiness", + "$640K – $1.3M" + ], + [ + "Process Discovery + Data Readiness + Technical Architecture", + "$380K – $1.0M" + ], + [ + "Process Discovery + Data Readiness + Technical Architecture", + "$380K – $760K" + ] + ], + "hovertemplate": "%{customdata[0]}
Unlocked: %{customdata[1]}", + "marker": { + "color": "#1baf7a", + "line": { + "color": "#fcfcfb", + "width": 2 + } + }, + "name": "Annual value unlocked (range)", + "type": "bar", + "x": [ + "1 · Data Readiness
level 2 → 3", + "2 · joint lift ×3
level 3 → 4", + "3 · joint lift ×3
level 4 → 5" + ], + "y": [ + 635625.0, + 635624.9999999998, + 381375.00000000006 + ] + } + ], + "layout": { + "bargap": 0.35, + "bargroupgap": 0.12, + "barmode": "group", + "font": { + "color": "#52514e", + "family": "system-ui, -apple-system, \"Segoe UI\", sans-serif", + "size": 13 + }, + "height": 420, + "legend": { + "font": { + "color": "#52514e", + "size": 11 + }, + "orientation": "h", + "x": 0, + "y": -0.12, + "yanchor": "top" + }, + "margin": { + "b": 60, + "l": 70, + "r": 30, + "t": 70 + }, + "paper_bgcolor": "#fcfcfb", + "plot_bgcolor": "#fcfcfb", + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "font": { + "color": "#0b0b0b", + "size": 16 + }, + "text": "Unlock sequence
sequential moves — each is the prerequisite of the next", + "x": 0.02, + "xanchor": "left" + }, + "xaxis": { + "showgrid": false, + "tickangle": 0, + "tickfont": { + "color": "#52514e", + "size": 12 + } + }, + "yaxis": { + "gridcolor": "#e1e0d9", + "tickfont": { + "color": "#898781" + }, + "tickformat": "$~s", + "zerolinecolor": "#c3c2b7" + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MoveCompetenciesLiftEst. costWeeksAnnual value unlockedNote
1Data Readiness2 → 3$300K – $600K12$640K – $1.3M
2Process Discovery + Data Readiness + Technical Architecture3 → 4$800K – $1.6M16$380K – $1.0Mjoint lift — the tied competencies must move together to shift the cap
3Process Discovery + Data Readiness + Technical Architecture4 → 5$1.0M – $2.1M20$380K – $760Kjoint lift — the tied competencies must move together to shift the cap
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── Stage: live analysis & visuals ──────────────────────────────────\n", + "heatmap_fig(heatmap_grid(CONFIG, SCORES)).show()\n", + "\n", + "if CONFIG.value_drivers:\n", + " value_bands_fig(VAS).show()\n", + " split_fig(VAS).show()\n", + " unlock_fig(VAS, CONFIG).show()\n", + " # The unlock moves as a table — the room verifies numbers by\n", + " # reading them, not by trusting the bars.\n", + " UNLOCK_DF = pd.DataFrame([{\n", + " \"Move\": _i + 1,\n", + " \"Competencies\": \" + \".join(CONFIG.competency(c).name\n", + " for c in _m.competency_ids),\n", + " \"Lift\": f\"{_m.current_level} → {_m.target_level}\",\n", + " \"Est. cost\": (f\"{money(_m.est_cost_low)} – {money(_m.est_cost_high)}\"\n", + " if _m.est_cost_low is not None else \"not configured\"),\n", + " \"Weeks\": _m.est_weeks if _m.est_weeks is not None else \"—\",\n", + " \"Annual value unlocked\": (f\"{money(_m.value_unlocked_low)} – \"\n", + " f\"{money(_m.value_unlocked_high)}\"),\n", + " \"Note\": _m.note,\n", + " } for _i, _m in enumerate(VAS.unlock_sequence)])\n", + " display(UNLOCK_DF.style.hide(axis=\"index\"))\n", + "else:\n", + " _ = mr.Markdown(text=(\n", + " f'
'\n", + " f'{esc(CONFIG.display_name)} has no value '\n", + " f'drivers configured yet — capability scoring works normally, but '\n", + " f'value-at-stake needs drivers in '\n", + " f'configs/{esc(INDUSTRY)}.yaml.
'))" + ] + }, + { + "cell_type": "markdown", + "id": "13fc62dc", + "metadata": {}, + "source": [ + "## Export\n", + "\n", + "The button writes `exports/{engagement_id}.json` — the full engagement\n", + "record, the source-of-truth artifact — and `exports/{engagement_id}.csv`,\n", + "one row per competency for cross-engagement analysis. A **deliberate\n", + "snapshot**: it captures the state at click time; click again after\n", + "changes to refresh." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c5270335", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:39.734876Z", + "iopub.status.busy": "2026-07-19T23:45:39.734657Z", + "iopub.status.idle": "2026-07-19T23:45:39.752517Z", + "shell.execute_reply": "2026-07-19T23:45:39.742714Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "a32316625a884fa5887079be7390601f", + "position": "inline", + "widget": "ButtonWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "a32316625a884fa5887079be7390601f", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── Export trigger (widgets ONLY — the click is handled below) ──────\n", + "_export_w = mr.Button(label=\"Export JSON + CSV\", position=\"inline\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "6102b26e", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:39.754715Z", + "iopub.status.busy": "2026-07-19T23:45:39.754547Z", + "iopub.status.idle": "2026-07-19T23:45:39.759379Z", + "shell.execute_reply": "2026-07-19T23:45:39.758332Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "No export click this run — engagement exports come from the stage button; report sources from scripts/export_report.py.\n" + ] + } + ], + "source": [ + "# ── Export on click — snapshot semantics ────────────────────────────\n", + "# Kernel globals persist across Mercury re-runs; the guard writes\n", + "# exactly once per click, at whatever state the cockpit showed then.\n", + "try:\n", + " _LAST_EXPORT_CLICKS\n", + "except NameError:\n", + " _LAST_EXPORT_CLICKS = 0\n", + "\n", + "if int(_export_w.n_clicks) > _LAST_EXPORT_CLICKS:\n", + " _json_path, _csv_path = write_exports(ENGAGEMENT, CONFIG, EXPORTS_DIR)\n", + " _LAST_EXPORT_CLICKS = int(_export_w.n_clicks)\n", + " print(f\"Exported {_json_path.name} + {_csv_path.name} → exports/\")\n", + "else:\n", + " backstage(\"No export click this run — engagement exports come from the \"\n", + " \"stage button; report sources from scripts/export_report.py.\")" + ] + }, + { + "cell_type": "markdown", + "id": "d7e31813", + "metadata": {}, + "source": [ + "## Verification & assertions\n", + "\n", + "Engine pins use the explicit seed scenario, independent of the sidebar,\n", + "so the gate tests `diaglib` + `configs/`, not the current session;\n", + "live-state pins are guarded so a facilitator moving a slider never\n", + "crashes the room; structural ties hold at **any** widget state. This\n", + "cell must pass under headless `nbconvert --execute` — it is the study's\n", + "smoke test. Output renders backstage only." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "783bee1d", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:39.761329Z", + "iopub.status.busy": "2026-07-19T23:45:39.761202Z", + "iopub.status.idle": "2026-07-19T23:45:39.788813Z", + "shell.execute_reply": "2026-07-19T23:45:39.788027Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All assertions passed.\n" + ] + } + ], + "source": [ + "# ── Verification gate — must pass under headless nbconvert ──────────\n", + "def _approx(got, want, tol=0.5):\n", + " assert abs(got - want) <= tol, f\"got {got:,.2f}, want {want:,.2f}\"\n", + "\n", + "\n", + "# Engine pins — EXPLICIT seed scenario, independent of widget state.\n", + "# Hand arithmetic in tests/test_value_math.py (same scenario).\n", + "_gate_cfg = load_config(\"contact_center\", CONFIGS_DIR)\n", + "_gate_baseline = OperationalBaseline(\n", + " annual_contact_volume=1_200_000, blended_cost_per_contact=6.50,\n", + " agent_headcount=450, annual_attrition_rate=0.30,\n", + " current_containment_rate=0.20, average_handle_time_seconds=420)\n", + "_gate_scores = build_scores(_gate_cfg, SEED_SCORES,\n", + " scored_at=dt.datetime(2026, 7, 19, 9, 0))\n", + "_gate_vas = value_at_stake(_gate_cfg, _gate_baseline, _gate_scores)\n", + "_approx(_gate_vas.theoretical_annual_value_low, 2_542_500)\n", + "_approx(_gate_vas.theoretical_annual_value_high, 5_085_000)\n", + "_approx(_gate_vas.realizable_18mo_low, 953_437.50)\n", + "_approx(_gate_vas.realizable_18mo_high, 3_051_000)\n", + "_approx(_gate_vas.trapped_value_low, 1_525_500)\n", + "_approx(_gate_vas.trapped_value_high, 3_813_750)\n", + "assert _gate_vas.binding_constraints == [\"data_readiness\"]\n", + "assert len(_gate_vas.unlock_sequence) == 3\n", + "_m1 = _gate_vas.unlock_sequence[0]\n", + "assert _m1.competency_ids == [\"data_readiness\"]\n", + "assert (_m1.est_cost_low, _m1.est_cost_high, _m1.est_weeks) == (300_000, 600_000, 12)\n", + "_approx(_m1.value_unlocked_low, 635_625)\n", + "_approx(_m1.value_unlocked_high, 1_271_250)\n", + "\n", + "# Live-state pins — guarded, so a moved slider can't crash the room.\n", + "_at_default = (\n", + " INDUSTRY == \"contact_center\"\n", + " and all(getattr(BASELINE, f) == getattr(_gate_baseline, f)\n", + " for f in BASELINE_FIELDS)\n", + " and all(RAW_SCORES[k][0] == SEED_SCORES[k][0] for k in SEED_SCORES))\n", + "if _at_default:\n", + " _approx(VAS.theoretical_annual_value_low, 2_542_500)\n", + " _approx(VAS.realizable_18mo_high, 3_051_000)\n", + " _approx(VAS.trapped_value_high, 3_813_750)\n", + "\n", + "# Structural ties — hold at ANY widget state.\n", + "assert len(SCORES) == 12 and len({s.competency_id for s in SCORES}) == 12\n", + "assert VAS.theoretical_annual_value_low <= VAS.theoretical_annual_value_high\n", + "assert VAS.realizable_18mo_low <= VAS.realizable_18mo_high\n", + "assert VAS.trapped_value_low <= VAS.trapped_value_high\n", + "_approx(sum(d.theoretical_low for d in VAS.driver_values),\n", + " VAS.theoretical_annual_value_low)\n", + "_approx(sum(d.theoretical_high for d in VAS.driver_values),\n", + " VAS.theoretical_annual_value_high)\n", + "_approx(VAS.realizable_18mo_low,\n", + " VAS.theoretical_annual_value_low * VAS.realization_factor_low * 1.5)\n", + "_approx(VAS.realizable_18mo_high,\n", + " VAS.theoretical_annual_value_high * VAS.realization_factor_high * 1.5)\n", + "assert set(VAS.binding_constraints) <= set(CONFIG.foundational_competencies)\n", + "assert len(VAS.unlock_sequence) <= 3\n", + "\n", + "# Export payload is serializable and matches the live session.\n", + "import json as _json\n", + "_payload = _json.loads(engagement_json(ENGAGEMENT))\n", + "assert _payload[\"engagement_id\"] == ENGAGEMENT.engagement_id\n", + "assert len(_payload[\"scores\"]) == 12\n", + "_df = scores_dataframe(ENGAGEMENT, CONFIG)\n", + "assert list(_df.columns) == CSV_COLUMNS and len(_df) == 12\n", + "\n", + "backstage(\"All assertions passed.\")" + ] + }, + { + "cell_type": "markdown", + "id": "1913a663", + "metadata": {}, + "source": [ + "## Data appendix — for the machines\n", + "\n", + "The full engagement as markdown tables plus one JSON block of state, so\n", + "the exported report is complete LLM input — and the future Athena\n", + "study-export payload. Renders **backstage** — hidden on the Mercury\n", + "stage." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "4451b2fe", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:39.791499Z", + "iopub.status.busy": "2026-07-19T23:45:39.791353Z", + "iopub.status.idle": "2026-07-19T23:45:39.798212Z", + "shell.execute_reply": "2026-07-19T23:45:39.797618Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "#### Capability scores\n", + "\n", + "| Competency | Dimension | Score | Evidence |\n", + "|---|---|---:|---|\n", + "| Automation & AI Strategy | Strategy & Value | 2 | AI driven by board pressure; no written thesis |\n", + "| Value Realization | Strategy & Value | 2 | Business cases pre-investment only |\n", + "| Executive Alignment | Strategy & Value | 3 | COO owns CX AI; steering meets quarterly |\n", + "| Process Discovery | Foundations | 3 | Top 10 call reasons mapped with volumes |\n", + "| Data Readiness | Foundations | 2 | KB stale; interaction data siloed in recordings |\n", + "| Technical Architecture | Foundations | 3 | CCaaS APIs available; shared integration layer WIP |\n", + "| Use Case Prioritization | Delivery | 3 | Scored backlog reviewed monthly |\n", + "| Delivery Capability | Delivery | 3 | Two bots in production via SI partner |\n", + "| Talent & Skills | Delivery | 2 | One conversation designer, contractor |\n", + "| AI Operations | Sustain | 2 | Containment eyeballed weekly, no drift alerts |\n", + "| Change & Adoption | Sustain | 3 | Agent champions for copilot rollout |\n", + "| Governance & Risk | Sustain | 3 | AI policy signed; review board for voice bots |\n", + "\n", + "#### Dimension rollup\n", + "\n", + "| Dimension | Mean score |\n", + "|---|---:|\n", + "| Strategy & Value | 2.33 |\n", + "| Foundations | 2.67 |\n", + "| Delivery | 2.67 |\n", + "| Sustain | 2.67 |\n", + "\n", + "#### Value drivers (theoretical annual)\n", + "\n", + "| Driver | Low | High |\n", + "|---|---:|---:|\n", + "| Deflection / containment improvement | $1.2M | $2.7M |\n", + "| Average handle time reduction | $1.2M | $2.0M |\n", + "| Attrition reduction | $200K | $400K |\n", + "| **Total** | **$2.5M** | **$5.1M** |\n", + "\n", + "Realization band at weakest foundation level 2: 25%-40% · realizable 18-mo $950K-$3.1M · trapped $1.5M-$3.8M per year · binding: data_readiness\n", + "\n", + "#### Engagement state (JSON)\n", + "\n", + "```json\n", + "{\n", + " \"engagement_id\": \"acme_demo_co_2026-07-19\",\n", + " \"client_name\": \"Acme Demo Co\",\n", + " \"industry_config\": \"contact_center\",\n", + " \"facilitator\": \"Robert Helewka\",\n", + " \"workshop_date\": \"2026-07-19\",\n", + " \"participants\": [\n", + " {\n", + " \"name\": \"Jane Example\",\n", + " \"role\": \"VP Customer Experience\",\n", + " \"function\": \"cx\"\n", + " },\n", + " {\n", + " \"name\": \"Sam Sample\",\n", + " \"role\": \"Contact Center Ops Director\",\n", + " \"function\": \"ops\"\n", + " }\n", + " ],\n", + " \"operational_baseline\": {\n", + " \"annual_contact_volume\": 1200000,\n", + " \"blended_cost_per_contact\": 6.5,\n", + " \"agent_headcount\": 450,\n", + " \"annual_attrition_rate\": 0.3,\n", + " \"current_containment_rate\": 0.2,\n", + " \"average_handle_time_seconds\": 420,\n", + " \"csat_baseline\": null,\n", + " \"revenue_at_risk\": null,\n", + " \"field_confidence\": {\n", + " \"annual_contact_volume\": \"known\",\n", + " \"blended_cost_per_contact\": \"estimated\",\n", + " \"agent_headcount\": \"known\",\n", + " \"annual_attrition_rate\": \"estimated\",\n", + " \"current_containment_rate\": \"estimated\",\n", + " \"average_handle_time_seconds\": \"known\"\n", + " }\n", + " },\n", + " \"scores\": [\n", + " {\n", + " \"competency_id\": \"automation_ai_strategy\",\n", + " \"dimension\": \"strategy_value\",\n", + " \"score\": 2,\n", + " \"evidence\": \"AI driven by board pressure; no written thesis\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"value_realization\",\n", + " \"dimension\": \"strategy_value\",\n", + " \"score\": 2,\n", + " \"evidence\": \"Business cases pre-investment only\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"executive_alignment\",\n", + " \"dimension\": \"strategy_value\",\n", + " \"score\": 3,\n", + " \"evidence\": \"COO owns CX AI; steering meets quarterly\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"process_discovery\",\n", + " \"dimension\": \"foundations\",\n", + " \"score\": 3,\n", + " \"evidence\": \"Top 10 call reasons mapped with volumes\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"data_readiness\",\n", + " \"dimension\": \"foundations\",\n", + " \"score\": 2,\n", + " \"evidence\": \"KB stale; interaction data siloed in recordings\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"technical_architecture\",\n", + " \"dimension\": \"foundations\",\n", + " \"score\": 3,\n", + " \"evidence\": \"CCaaS APIs available; shared integration layer WIP\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"use_case_prioritization\",\n", + " \"dimension\": \"delivery\",\n", + " \"score\": 3,\n", + " \"evidence\": \"Scored backlog reviewed monthly\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"delivery_capability\",\n", + " \"dimension\": \"delivery\",\n", + " \"score\": 3,\n", + " \"evidence\": \"Two bots in production via SI partner\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"talent_and_skills\",\n", + " \"dimension\": \"delivery\",\n", + " \"score\": 2,\n", + " \"evidence\": \"One conversation designer, contractor\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"ai_operations\",\n", + " \"dimension\": \"sustain\",\n", + " \"score\": 2,\n", + " \"evidence\": \"Containment eyeballed weekly, no drift alerts\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"change_adoption\",\n", + " \"dimension\": \"sustain\",\n", + " \"score\": 3,\n", + " \"evidence\": \"Agent champions for copilot rollout\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " },\n", + " {\n", + " \"competency_id\": \"governance_and_risk\",\n", + " \"dimension\": \"sustain\",\n", + " \"score\": 3,\n", + " \"evidence\": \"AI policy signed; review board for voice bots\",\n", + " \"scorer_role\": \"facilitator\",\n", + " \"scored_at\": \"2026-07-19T19:45:38.063130\"\n", + " }\n", + " ],\n", + " \"computed_value\": {\n", + " \"theoretical_annual_value_low\": 2542500.0,\n", + " \"theoretical_annual_value_high\": 5085000.0,\n", + " \"realizable_18mo_low\": 953437.5,\n", + " \"realizable_18mo_high\": 3051000.0,\n", + " \"trapped_value_low\": 1525500.0,\n", + " \"trapped_value_high\": 3813750.0,\n", + " \"binding_constraints\": [\n", + " \"data_readiness\"\n", + " ],\n", + " \"unlock_sequence\": [\n", + " {\n", + " \"competency_ids\": [\n", + " \"data_readiness\"\n", + " ],\n", + " \"current_level\": 2,\n", + " \"target_level\": 3,\n", + " \"est_cost_low\": 300000.0,\n", + " \"est_cost_high\": 600000.0,\n", + " \"est_weeks\": 12,\n", + " \"value_unlocked_low\": 635625.0,\n", + " \"value_unlocked_high\": 1271250.0,\n", + " \"note\": \"\"\n", + " },\n", + " {\n", + " \"competency_ids\": [\n", + " \"process_discovery\",\n", + " \"data_readiness\",\n", + " \"technical_architecture\"\n", + " ],\n", + " \"current_level\": 3,\n", + " \"target_level\": 4,\n", + " \"est_cost_low\": 800000.0,\n", + " \"est_cost_high\": 1600000.0,\n", + " \"est_weeks\": 16,\n", + " \"value_unlocked_low\": 381375.00000000006,\n", + " \"value_unlocked_high\": 1016999.9999999998,\n", + " \"note\": \"joint lift — the tied competencies must move together to shift the cap\"\n", + " },\n", + " {\n", + " \"competency_ids\": [\n", + " \"process_discovery\",\n", + " \"data_readiness\",\n", + " \"technical_architecture\"\n", + " ],\n", + " \"current_level\": 4,\n", + " \"target_level\": 5,\n", + " \"est_cost_low\": 1050000.0,\n", + " \"est_cost_high\": 2100000.0,\n", + " \"est_weeks\": 20,\n", + " \"value_unlocked_low\": 381375.00000000006,\n", + " \"value_unlocked_high\": 762750.0000000001,\n", + " \"note\": \"joint lift — the tied competencies must move together to shift the cap\"\n", + " }\n", + " ],\n", + " \"weakest_foundational_score\": 2,\n", + " \"realization_factor_low\": 0.25,\n", + " \"realization_factor_high\": 0.4,\n", + " \"driver_values\": [\n", + " {\n", + " \"driver_id\": \"deflection_lift\",\n", + " \"name\": \"Deflection / containment improvement\",\n", + " \"theoretical_low\": 1170000.0,\n", + " \"theoretical_high\": 2730000.0\n", + " },\n", + " {\n", + " \"driver_id\": \"aht_reduction\",\n", + " \"name\": \"Average handle time reduction\",\n", + " \"theoretical_low\": 1170000.0,\n", + " \"theoretical_high\": 1950000.0\n", + " },\n", + " {\n", + " \"driver_id\": \"attrition_reduction\",\n", + " \"name\": \"Attrition reduction\",\n", + " \"theoretical_low\": 202500.0,\n", + " \"theoretical_high\": 405000.0\n", + " }\n", + " ],\n", + " \"warnings\": []\n", + " },\n", + " \"notes\": \"\"\n", + "}\n", + "```\n" + ] + } + ], + "source": [ + "# ── Data appendix — LLM-readable dump of the engagement ─────────────\n", + "# Renders backstage only (JupyterLab / nbconvert exports).\n", + "backstage(\"#### Capability scores\\n\")\n", + "_rows = [\"| Competency | Dimension | Score | Evidence |\", \"|---|---|---:|---|\"]\n", + "for _s in SCORES:\n", + " _cc = CONFIG.competency(_s.competency_id)\n", + " _ev = _s.evidence.replace(\"|\", \"\\\\|\") or \"—\"\n", + " _rows.append(f\"| {_cc.name} | {DIMENSION_NAME[_s.dimension]} | \"\n", + " f\"{_s.score} | {_ev} |\")\n", + "backstage(\"\\n\".join(_rows))\n", + "\n", + "backstage(\"\\n#### Dimension rollup\\n\")\n", + "_rows = [\"| Dimension | Mean score |\", \"|---|---:|\"]\n", + "for _did, _dname, _mean in dimension_rollup(CONFIG, SCORES):\n", + " _rows.append(f\"| {_dname} | {_mean:.2f} |\")\n", + "backstage(\"\\n\".join(_rows))\n", + "\n", + "if CONFIG.value_drivers:\n", + " backstage(\"\\n#### Value drivers (theoretical annual)\\n\")\n", + " _rows = [\"| Driver | Low | High |\", \"|---|---:|---:|\"]\n", + " for _d in VAS.driver_values:\n", + " _rows.append(f\"| {_d.name} | {money(_d.theoretical_low)} | \"\n", + " f\"{money(_d.theoretical_high)} |\")\n", + " _rows.append(f\"| **Total** | **{money(VAS.theoretical_annual_value_low)}** \"\n", + " f\"| **{money(VAS.theoretical_annual_value_high)}** |\")\n", + " backstage(\"\\n\".join(_rows))\n", + " backstage(f\"\\nRealization band at weakest foundation level \"\n", + " f\"{VAS.weakest_foundational_score}: \"\n", + " f\"{VAS.realization_factor_low:.0%}-{VAS.realization_factor_high:.0%} · \"\n", + " f\"realizable 18-mo {money(VAS.realizable_18mo_low)}-\"\n", + " f\"{money(VAS.realizable_18mo_high)} · trapped \"\n", + " f\"{money(VAS.trapped_value_low)}-{money(VAS.trapped_value_high)} \"\n", + " f\"per year · binding: {', '.join(VAS.binding_constraints)}\")\n", + "\n", + "backstage(\"\\n#### Engagement state (JSON)\\n\")\n", + "backstage(\"```json\")\n", + "backstage(engagement_json(ENGAGEMENT))\n", + "backstage(\"```\")" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "d3272e77", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:45:39.799620Z", + "iopub.status.busy": "2026-07-19T23:45:39.799494Z", + "iopub.status.idle": "2026-07-19T23:45:39.806031Z", + "shell.execute_reply": "2026-07-19T23:45:39.801884Z" + } + }, + "outputs": [], + "source": [ + "# ── Review a saved engagement (backstage utility, optional) ─────────\n", + "# Point _REVIEW_JSON at an exports/*.json and run in JupyterLab to\n", + "# reload a past engagement for review; the live session is untouched.\n", + "_REVIEW_JSON = \"\"\n", + "if _REVIEW_JSON:\n", + " from diaglib import load_engagement\n", + " _prev = load_engagement(pathlib.Path(_REVIEW_JSON))\n", + " backstage(f\"loaded {_prev.engagement_id}: {_prev.client_name} · \"\n", + " f\"{len(_prev.scores)} scores · \" + (\n", + " \"binding: \" + \", \".join(_prev.computed_value.binding_constraints)\n", + " if _prev.computed_value else \"no computed value\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.7" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "0134ad746d16416390a46248fe5e1aa3": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "1 · Automation & AI Strategy", + "2 · Value Realization", + "3 · Executive Alignment", + "4 · Process Discovery", + "5 · Data Readiness", + "6 · Technical Architecture", + "7 · Use Case Prioritization", + "8 · Delivery Capability", + "9 · Talent & Skills", + "10 · AI Operations", + "11 · Change & Adoption", + "12 · Governance & Risk" + ], + "disabled": false, + "hidden": false, + "label": "Now scoring", + "layout": "IPY_MODEL_ac26fdaac4174281bce0b305c73f706e", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "1 · Automation & AI Strategy" + } + }, + "0384abc193994b69881674157eb6b28f": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_610bb2af251a408ab9e2be886b901705", + "layout_path": null, + "placeholder": "​", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_f86046c7d0fb4a79bf086f572ae62e00", + "tabbable": null, + "tooltip": null, + "value": "

2 · Operational baseline

" + } + }, + "038b606123d74acd96d5e5b4581b409b": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "0ad924ecfd3544a8b982c2cefa3c2711": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "0ff9441dcf9947f5a45714eaf9ae9d54": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "10af45726b014b8a9bc5ca00fe713542": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "114ea157213646ccba3e4a6ea52c2856": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_bd2aa3a869924783b6f555b34d8ea40e", + "layout_path": null, + "placeholder": "​", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_8a1ab813e289451aa5f34526f8e0737e", + "tabbable": null, + "tooltip": null, + "value": "

Foundations

" + } + }, + "12b153c6fe8d4f7db07a58270abc11d8": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — AI Operations", + "layout": "IPY_MODEL_6f5a203d97274d19904c0bb9033decb6", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 2 + } + }, + "1b52fe1f13244689890ce4228dd759bd": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "1dd77bf8ef284086a98c3f506dac122d": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Value Realization", + "layout": "IPY_MODEL_a28bd95a94df42179c0b2c182073295e", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Business cases pre-investment only" + } + }, + "1e1189045b604913a5383ec4b05aff36": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "1e974ed77efd47a799a206ac2876d7f7": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "25453e259ab74dfc84ec36936f484d21": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "275ca35bfb974e3bab5d507f521fc4c2": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Change & Adoption", + "layout": "IPY_MODEL_e87bd4c43bc247b48eba80646bacc41b", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 3 + } + }, + "2782d2713dfc449aaa69d11007cace4e": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.date.DateInputWidget", + "_css": "\n .mljar-date-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-date-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-date-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n box-sizing: border-box;\n line-height: 1.4;\n }\n\n .mljar-date-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-date-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n @media (max-width: 768px) {\n .mljar-date-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-date-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-date-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"date\";\n input.classList.add(\"mljar-date-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Date\";\n input.value = model.get(\"value\") || \"\";\n\n const min = model.get(\"min\") || \"\";\n const max = model.get(\"max\") || \"\";\n if (min) input.min = min; else input.removeAttribute(\"min\");\n if (max) input.max = max; else input.removeAttribute(\"max\");\n\n input.disabled = !!model.get(\"disabled\");\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n model.save_changes();\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Workshop date", + "layout": "IPY_MODEL_fd25d64cd05848d7958943957f7bd4a8", + "layout_path": null, + "max": "", + "min": "", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "2026-07-19" + } + }, + "27875b6048174bd1985274a42a0d3945": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "2a2adb61fc124e4a8a489f341024af9d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "2ebb37baa8404d2cabcaa2069aa1c212": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "2ef89a29c65c4d978ec5ced9504dba73": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Session notes", + "layout": "IPY_MODEL_27875b6048174bd1985274a42a0d3945", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "" + } + }, + "333656890d3a4dce8a18171604757325": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_0ad924ecfd3544a8b982c2cefa3c2711", + "layout_path": null, + "placeholder": "​", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_038b606123d74acd96d5e5b4581b409b", + "tabbable": null, + "tooltip": null, + "value": "

Sustain

" + } + }, + "33c48116b82842f8b1a571804a90ebca": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — AI Operations", + "layout": "IPY_MODEL_93574dd500a84b89aa94f05b5ba94a80", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Containment eyeballed weekly, no drift alerts" + } + }, + "36927983549046499f7d080a20c1b0b8": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Delivery Capability", + "layout": "IPY_MODEL_1e974ed77efd47a799a206ac2876d7f7", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 3 + } + }, + "39ce7dffb71b41b7a2d6f14e63b2ad15": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Process Discovery", + "layout": "IPY_MODEL_d09a3c1bbcd24f1f86cb58a767a59a60", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 3 + } + }, + "40697a7b3df442ffb315149b61aaa646": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Change & Adoption", + "layout": "IPY_MODEL_707cddf03ec34123a416f7b22e3b71b6", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Agent champions for copilot rollout" + } + }, + "42c73613a5b44fdcb4113156c70012a0": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "45b419ade2d446f887aefbcc8167ba6a": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Use Case Prioritization", + "layout": "IPY_MODEL_d8226a602bb84ef8898dfb8b66007001", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 3 + } + }, + "4b2a68f2a2a7491aa8a3fbee02365047": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "4bbea152c5354344bad9cae9ae4b131f": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_aa44af8d77fb41ad885aa091b4f6f537", + "layout_path": null, + "placeholder": "​", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_915770f5a3354ee1812203cedd0266cb", + "tabbable": null, + "tooltip": null, + "value": "

3 · Capability scoring

" + } + }, + "508f349cd9c9427e99d1a47c6cfcef51": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "58a702be2cb942929305bed89ee052cc": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "5c48b8be8ec14795ae22f3bc29e083fc": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "5cc39b1eef054bc9a484708bbcf282ee": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Data Readiness", + "layout": "IPY_MODEL_a9e69ba0e42443bfae92ade55d144b11", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 2 + } + }, + "5feaf4858ee043a8b09f3507ce84f49c": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_d99bfdd7c8144a5793f3c6fcc0153738", + "layout_path": null, + "placeholder": "​", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_afb9325b4b9a49be9b56e02669e85d07", + "tabbable": null, + "tooltip": null, + "value": "

1 · Engagement

" + } + }, + "60fabcff9f5e4a37942bb364eccddb85": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Average handle time (seconds)", + "layout": "IPY_MODEL_d0d3383dcf3d4af8b765a09d74644425", + "layout_path": null, + "max": 3600.0, + "min": 0.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 10.0, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 420.0 + } + }, + "610bb2af251a408ab9e2be886b901705": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "629f019ab17c4adfb3a0518af63453e8": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "6e04107870054b609461f8468f8117bf": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "6f5a203d97274d19904c0bb9033decb6": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "707cddf03ec34123a416f7b22e3b71b6": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "71ff8c98d8bb4c7096c0ea8a1b693def": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "738b9403a2cb4d3498f2e174430c6d5b": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Executive Alignment", + "layout": "IPY_MODEL_10af45726b014b8a9bc5ca00fe713542", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 3 + } + }, + "73ab01b6ab4843b68ab1930a1b112e7a": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "741f4d5aeaf34ea6bebbba0b72f23426": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Technical Architecture", + "layout": "IPY_MODEL_2a2adb61fc124e4a8a489f341024af9d", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 3 + } + }, + "74ca96bfbd7a44c7a87eb3c1e0a895e0": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Governance & Risk", + "layout": "IPY_MODEL_cc1eb0191f3840e5a9af90a9b1dd7a49", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 3 + } + }, + "780c3efc5ec54ecc9ea40ce81f52cc28": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "🟢 known", + "🟡 estimated", + "🔴 unknown" + ], + "disabled": false, + "hidden": false, + "label": "Average handle time (seconds) — confidence", + "layout": "IPY_MODEL_6e04107870054b609461f8468f8117bf", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "🟢 known" + } + }, + "7aa2b22ed12d4c1a9ff00e2432464da8": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Talent & Skills", + "layout": "IPY_MODEL_c84dfde6c7794e49907e69ef4ba27e57", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 2 + } + }, + "82b3e6f7ce29429b94f0beb47b226b59": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Use Case Prioritization", + "layout": "IPY_MODEL_8e0f8f895e244b24a2d00d6bbe064f50", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Scored backlog reviewed monthly" + } + }, + "878ac4372b24422d9e06d9c6a77ed9b2": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Blended cost per contact ($)", + "layout": "IPY_MODEL_58a702be2cb942929305bed89ee052cc", + "layout_path": null, + "max": 100.0, + "min": 0.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 0.25, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 6.5 + } + }, + "8843aabb37b748a78228f4b18c49e6aa": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Annual attrition rate (0-1)", + "layout": "IPY_MODEL_f24ef21b03f04b90aaad8349a7f2ce48", + "layout_path": null, + "max": 1.0, + "min": 0.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 0.01, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 0.3 + } + }, + "8a1ab813e289451aa5f34526f8e0737e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "8bb4e603517a49d7a9976ee555dff224": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Talent & Skills", + "layout": "IPY_MODEL_ec91c552f127474f8796fdca5b55ddf6", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "One conversation designer, contractor" + } + }, + "8e0f8f895e244b24a2d00d6bbe064f50": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "8eaaa94d855d4747afed128c16d66308": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Automation & AI Strategy", + "layout": "IPY_MODEL_ede38c77a96945ca91a33dbe0c80c221", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 2 + } + }, + "90d4dc2d15514ebda566e852ce78bf73": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Current containment rate (0-1)", + "layout": "IPY_MODEL_71ff8c98d8bb4c7096c0ea8a1b693def", + "layout_path": null, + "max": 1.0, + "min": 0.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 0.01, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 0.2 + } + }, + "915770f5a3354ee1812203cedd0266cb": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "915ec41832064b9cb8b85fbcf17d028e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "93574dd500a84b89aa94f05b5ba94a80": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "955923ab919f4bce897169977d539ea5": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Facilitator", + "layout": "IPY_MODEL_dc331c6bb2614915837a1db56ca9f7ae", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Robert Helewka" + } + }, + "956c843fdb3847f6a6e9e8f07824acb9": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "🟢 known", + "🟡 estimated", + "🔴 unknown" + ], + "disabled": false, + "hidden": false, + "label": "Blended cost per contact ($) — confidence", + "layout": "IPY_MODEL_915ec41832064b9cb8b85fbcf17d028e", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "🟡 estimated" + } + }, + "96a1888c76f24e1ebc7f86c991ada96e": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Process Discovery", + "layout": "IPY_MODEL_0ff9441dcf9947f5a45714eaf9ae9d54", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Top 10 call reasons mapped with volumes" + } + }, + "9c7d24f3d7b64b3e858baaa83002d48d": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "🟢 known", + "🟡 estimated", + "🔴 unknown" + ], + "disabled": false, + "hidden": false, + "label": "Agent headcount — confidence", + "layout": "IPY_MODEL_a0b1e3e6878a47148a8c044aa98fb0dd", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "🟢 known" + } + }, + "9ede9faa5bc44112a30d3093c7709cbc": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_defd950214494c0981a4965bbb354bea", + "layout_path": null, + "placeholder": "​", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_1b52fe1f13244689890ce4228dd759bd", + "tabbable": null, + "tooltip": null, + "value": "

Strategy & Value

" + } + }, + "a002cefb6acf4098893088f19c7430d7": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "a0b1e3e6878a47148a8c044aa98fb0dd": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "a28bd95a94df42179c0b2c182073295e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "a32316625a884fa5887079be7390601f": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.button.ButtonWidget", + "_css": "\n .mljar-button-container {\n display: inline-flex;\n width: auto;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n padding-left: 4px;\n padding-right: 4px;\n }\n\n .mljar-button {\n border: 2px solid #007bff;\n background: #007bff;\n color: #ffffff;\n border-radius: 6px !important;\n padding: 6px 18px;\n margin-top: 5px;\n margin-bottom: 5px;\n cursor: pointer;\n transition: background 0.2s, color 0.2s, border-color 0.2s;\n user-select: none;\n outline: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n font-size: 1.08em;\n font-weight: 600;\n }\n\n .mljar-button:hover:not(:disabled) {\n background: #f3f3f4;\n color: #007bff;\n }\n\n .mljar-button:active:not(:disabled) {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-button:focus-visible {\n outline: none;\n border-color: #007bff;\n }\n\n .mljar-button:disabled {\n opacity: 0.8;\n cursor: not-allowed;\n }\n\n /* Variants */\n .mljar-button.is-primary {\n background: #007bff;\n color: #ffffff;\n border: 2px solid #007bff;\n }\n .mljar-button.is-primary:hover:not(:disabled) {\n background: #f3f3f4;\n color: #007bff;\n }\n\n .mljar-button.is-secondary {\n background: #ffffff;\n color: #0f172a;\n }\n\n .mljar-button.is-outline {\n background: transparent;\n color: #007bff;\n border: 2px solid #007bff;\n }\n .mljar-button.is-outline:hover:not(:disabled) {\n background: #f3f3f4;\n color: #007bff;\n }\n\n .mljar-button.is-danger {\n background: #dc3545;\n color: #fff;\n border-color: #dc3545;\n }\n .mljar-button.is-danger:hover:not(:disabled) {\n filter: brightness(0.98);\n background: #dc3545;\n color: #fff;\n }\n\n /* Sizes */\n .mljar-button.is-sm {\n padding: 4px 12px;\n font-size: 12px;\n border-radius: 4px;\n }\n .mljar-button.is-md {\n padding: 6px 18px;\n }\n .mljar-button.is-lg {\n padding: 8px 22px;\n font-size: 16px;\n border-radius: 10px;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-button-container\");\n\n const btn = document.createElement(\"button\");\n btn.classList.add(\"mljar-button\");\n\n function syncFromModel() {\n // label\n btn.textContent = model.get(\"label\") || \"Run\";\n\n // variant\n const v = model.get(\"variant\") || \"primary\";\n [\"is-primary\",\"is-secondary\",\"is-outline\",\"is-danger\"].forEach(c => btn.classList.remove(c));\n btn.classList.add(`is-${v}`);\n\n // size\n const s = model.get(\"size\") || \"md\";\n [\"is-sm\",\"is-md\",\"is-lg\"].forEach(c => btn.classList.remove(c));\n btn.classList.add(`is-${s}`);\n\n // disabled\n btn.disabled = !!model.get(\"disabled\");\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n btn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = model.get(\"n_clicks\") || 0;\n model.set(\"n_clicks\", current + 1);\n model.set(\"last_clicked_at\", new Date().toISOString());\n model.set(\"value\", true);\n model.save_changes();\n // model.send({ type: \"clicked\", n_clicks: current + 1 });\n });\n\n // Reactivity\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:variant\", syncFromModel);\n model.on(\"change:size\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n container.appendChild(btn);\n el.appendChild(container);\n\n syncFromModel();\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Export JSON + CSV", + "last_clicked_at": "", + "layout": "IPY_MODEL_e93aad95fc344e05a33c09ad369b21c3", + "layout_path": null, + "n_clicks": 0, + "position": "inline", + "render_slot_id": null, + "size": "md", + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "value": false, + "variant": "primary" + } + }, + "a57e5835f51a4a0ea099d86287ba82bf": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_5c48b8be8ec14795ae22f3bc29e083fc", + "layout_path": null, + "placeholder": "​", + "position": "inline", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_ef01e7fbeb1941ec8bfa0d387afe11fe", + "tabbable": null, + "tooltip": null, + "value": "
223323332233
Strategy & Value
Automation & AI Strategy
Is there a written thesis for why AI, where, and what it changes about the operating model?
\"We're doing AI because the CEO read an article.\"
1No thesis. AI driven by executive impulse or vendor pitch.
2Aspirational vision, no operating model implications defined.
3Documented strategy, partial linkage to operating model.
4Strategy drives portfolio decisions and operating model changes.
5Strategy is reviewed quarterly; operating model evolves with capability.
Evidence: AI driven by board pressure; no written thesis
" + } + }, + "a6270c5418dc418c8bfcf49cfd662cc4": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "a7000c769e234457a69473437aea7491": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_ef0dadfa61ff4ba0a581baac678f060c", + "layout_path": null, + "placeholder": "​", + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_629f019ab17c4adfb3a0518af63453e8", + "tabbable": null, + "tooltip": null, + "value": "

Delivery

" + } + }, + "a76214e4ed5548de8e248286ea47d040": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_42c73613a5b44fdcb4113156c70012a0", + "layout_path": null, + "placeholder": "​", + "position": "inline", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_f13438fbf2ef4d08948f8abc7386c998", + "tabbable": null, + "tooltip": null, + "value": "
Acme Demo Co — CX AI Diagnostic
Contact Center · 2026-07-19 · facilitated by Robert Helewka · evidence captured 12/12
Jane Example · VP Customer Experience cxSam Sample · Contact Center Ops Director ops
Operational baseline
Annual contact volume1,200,000🟢
Blended cost per contact ($)6.50🟡
Agent headcount450🟢
Annual attrition rate (0-1)0.30🟡
Current containment rate (0-1)0.20🟡
Average handle time (seconds)420🟢
" + } + }, + "a9e69ba0e42443bfae92ade55d144b11": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "aa44af8d77fb41ad885aa091b4f6f537": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ac26fdaac4174281bce0b305c73f706e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "afb9325b4b9a49be9b56e02669e85d07": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "b347ca14c69d40e8876ecb15b9f84241": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "b4527b9783fe43598a8d5846ac38e606": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "bae59fd8c40a4e16bde1f847d17c7192": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "contact_center", + "financial_services" + ], + "disabled": false, + "hidden": false, + "label": "Industry config", + "layout": "IPY_MODEL_c6902106d5354710b75eac5ba59d5beb", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "contact_center" + } + }, + "bd2aa3a869924783b6f555b34d8ea40e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "bdf928b007aa4132aefb644a6b6c751b": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Executive Alignment", + "layout": "IPY_MODEL_f2ac82071dce4a89b8b98630090cd470", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "COO owns CX AI; steering meets quarterly" + } + }, + "c0def29eb51e47f78e0c2bd3db3afc0a": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Data Readiness", + "layout": "IPY_MODEL_25453e259ab74dfc84ec36936f484d21", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "KB stale; interaction data siloed in recordings" + } + }, + "c6902106d5354710b75eac5ba59d5beb": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "c82b1adbfcd44ff88abd892f4fd78301": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "🟢 known", + "🟡 estimated", + "🔴 unknown" + ], + "disabled": false, + "hidden": false, + "label": "Current containment rate (0-1) — confidence", + "layout": "IPY_MODEL_b347ca14c69d40e8876ecb15b9f84241", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "🟡 estimated" + } + }, + "c84dfde6c7794e49907e69ef4ba27e57": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "cc160d674e60481695cd07ca5098e1ca": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Annual contact volume", + "layout": "IPY_MODEL_4b2a68f2a2a7491aa8a3fbee02365047", + "layout_path": null, + "max": 100000000.0, + "min": 0.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 10000.0, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 1200000.0 + } + }, + "cc1eb0191f3840e5a9af90a9b1dd7a49": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d06eb8adf9994ae89d82f3983fdcf24f": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d09a3c1bbcd24f1f86cb58a767a59a60": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d0d3383dcf3d4af8b765a09d74644425": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d34dbe00c35d4eb6b8a7da2340dbe2e1": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Participants — Name | Role | Function; ...", + "layout": "IPY_MODEL_a002cefb6acf4098893088f19c7430d7", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Jane Example | VP Customer Experience | cx; Sam Sample | Contact Center Ops Director | ops" + } + }, + "d48a2c7bbda8440aa87e9078553f38e9": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.slider.SliderWidget", + "_css": "\n .mljar-slider-container {\n --mljar-slider-thumb-size: 16px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n max-width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: hidden;\n box-sizing: border-box;\n }\n\n .mljar-slider-stage {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding-top: 20px;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-floating-value {\n position: absolute;\n top: 0;\n left: 8px;\n transform: translateX(-50%);\n color: #007bff;\n font-weight: 700;\n font-size: 0.95em;\n line-height: 1;\n text-align: center;\n white-space: nowrap;\n pointer-events: none;\n z-index: 1;\n }\n\n .mljar-slider-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n font-weight: 600;\n line-height: 1.2;\n }\n\n .mljar-slider-row {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n overflow: visible;\n box-sizing: border-box;\n }\n\n .mljar-slider-minmax-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n margin-top: 6px;\n color: #616673;\n font-size: 0.9em;\n line-height: 1.2;\n box-sizing: border-box;\n }\n\n .mljar-slider-min-label,\n .mljar-slider-max-label {\n color: inherit;\n white-space: nowrap;\n }\n\n .mljar-slider-input {\n display: block;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n background: transparent;\n -webkit-appearance: none;\n appearance: none;\n border: none;\n height: 24px;\n padding: 0;\n margin: 0;\n cursor: pointer;\n box-sizing: border-box;\n }\n\n .mljar-slider-input:focus {\n outline: none;\n }\n\n .mljar-slider-input:focus-visible::-webkit-slider-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n .mljar-slider-input:focus-visible::-moz-range-thumb {\n box-shadow: 0 0 0 3px #e6f2ff;\n }\n\n /* Track */\n .mljar-slider-input::-webkit-slider-runnable-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n margin: auto;\n }\n .mljar-slider-input::-moz-range-track {\n height: 6px;\n background: #e0e0e0;\n border-radius: 6px;\n }\n\n /* Thumb */\n .mljar-slider-input::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n margin-top: -5px;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n .mljar-slider-input::-moz-range-thumb {\n width: var(--mljar-slider-thumb-size);\n height: var(--mljar-slider-thumb-size);\n border-radius: 50%;\n background: #007bff;\n cursor: pointer;\n transition: transform 0.14s ease, background-color 0.14s ease;\n }\n\n .mljar-slider-input:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n\n .mljar-slider-input:disabled::-webkit-slider-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:disabled::-moz-range-thumb {\n cursor: not-allowed;\n transform: none;\n }\n\n .mljar-slider-input:active::-webkit-slider-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n .mljar-slider-input:active::-moz-range-thumb {\n transform: scale(1.08);\n background: #007bff;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-slider-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-slider-top-label\");\n\n const sliderStage = document.createElement(\"div\");\n sliderStage.classList.add(\"mljar-slider-stage\");\n\n const floatingValueLabel = document.createElement(\"div\");\n floatingValueLabel.classList.add(\"mljar-slider-floating-value\");\n\n const sliderRow = document.createElement(\"div\");\n sliderRow.classList.add(\"mljar-slider-row\");\n\n const slider = document.createElement(\"input\");\n slider.type = \"range\";\n slider.classList.add(\"mljar-slider-input\");\n\n const minMaxRow = document.createElement(\"div\");\n minMaxRow.classList.add(\"mljar-slider-minmax-row\");\n\n const minLabel = document.createElement(\"span\");\n minLabel.classList.add(\"mljar-slider-min-label\");\n\n const maxLabel = document.createElement(\"span\");\n maxLabel.classList.add(\"mljar-slider-max-label\");\n\n function positionFloatingValue() {\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const value = Number(model.get(\"value\"));\n const range = max - min;\n const ratio = range <= 0 ? 0 : (value - min) / range;\n const clampedRatio = Math.max(0, Math.min(1, ratio));\n const computed = getComputedStyle(container);\n const thumbSize =\n parseFloat(computed.getPropertyValue(\"--mljar-slider-thumb-size\")) || 16;\n const inputWidth = slider.clientWidth || 0;\n const stageWidth = sliderStage.clientWidth || inputWidth || 0;\n const labelWidth = floatingValueLabel.offsetWidth || 0;\n\n if (inputWidth <= 0 || stageWidth <= 0) {\n return;\n }\n\n const sliderOffsetLeft = slider.offsetLeft || 0;\n const usableWidth = Math.max(0, inputWidth - thumbSize);\n const idealCenter =\n sliderOffsetLeft + thumbSize / 2 + clampedRatio * usableWidth;\n const halfLabel = labelWidth / 2;\n const minCenter = halfLabel;\n const maxCenter = Math.max(halfLabel, stageWidth - halfLabel);\n const finalCenter = Math.min(Math.max(idealCenter, minCenter), maxCenter);\n\n floatingValueLabel.style.left = `${finalCenter}px`;\n }\n\n function syncFromModel() {\n slider.min = model.get(\"min\");\n slider.max = model.get(\"max\");\n slider.value = model.get(\"value\");\n floatingValueLabel.textContent = String(model.get(\"value\"));\n minLabel.textContent = String(model.get(\"min\"));\n maxLabel.textContent = String(model.get(\"max\"));\n\n slider.disabled = !!model.get(\"disabled\");\n topLabel.textContent = model.get(\"label\") || \"Select number\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"flex\";\n positionFloatingValue();\n }\n\n let debounceTimer = null;\n slider.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", Number(slider.value));\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n model.save_changes();\n }, 100);\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n sliderRow.appendChild(slider);\n minMaxRow.appendChild(minLabel);\n minMaxRow.appendChild(maxLabel);\n\n container.appendChild(topLabel);\n sliderStage.appendChild(floatingValueLabel);\n sliderStage.appendChild(sliderRow);\n sliderStage.appendChild(minMaxRow);\n container.appendChild(sliderStage);\n el.appendChild(container);\n\n syncFromModel();\n\n const resizeObserver = new ResizeObserver(() => {\n positionFloatingValue();\n });\n resizeObserver.observe(sliderStage);\n\n return () => {\n resizeObserver.disconnect();\n };\n\n // ---- read cell id (no DOM modifications) ----\n /*const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Score — Value Realization", + "layout": "IPY_MODEL_e534d8601c624342ba4cf97686d0d9f4", + "layout_path": null, + "max": 5, + "min": 1, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 2 + } + }, + "d59db85587a8467dae0addb485bc3cbc": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "🟢 known", + "🟡 estimated", + "🔴 unknown" + ], + "disabled": false, + "hidden": false, + "label": "Annual contact volume — confidence", + "layout": "IPY_MODEL_508f349cd9c9427e99d1a47c6cfcef51", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "🟢 known" + } + }, + "d7940b33fc6f484582428064dfc25d0d": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Governance & Risk", + "layout": "IPY_MODEL_a6270c5418dc418c8bfcf49cfd662cc4", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "AI policy signed; review board for voice bots" + } + }, + "d8226a602bb84ef8898dfb8b66007001": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d885ae9c19e744248b31df0a37c3e498": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d99bfdd7c8144a5793f3c6fcc0153738": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "dc331c6bb2614915837a1db56ca9f7ae": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "defd950214494c0981a4965bbb354bea": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e534d8601c624342ba4cf97686d0d9f4": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e87bd4c43bc247b48eba80646bacc41b": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e91abb56e78a484598c5d47806b26282": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Delivery Capability", + "layout": "IPY_MODEL_2ebb37baa8404d2cabcaa2069aa1c212", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Two bots in production via SI partner" + } + }, + "e93aad95fc344e05a33c09ad369b21c3": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ec1d09aab4cd43d7821005f37d7acd59": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "🟢 known", + "🟡 estimated", + "🔴 unknown" + ], + "disabled": false, + "hidden": false, + "label": "Annual attrition rate (0-1) — confidence", + "layout": "IPY_MODEL_73ab01b6ab4843b68ab1930a1b112e7a", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "🟡 estimated" + } + }, + "ec91c552f127474f8796fdca5b55ddf6": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ede38c77a96945ca91a33dbe0c80c221": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "eecaf52a0a074f02a04efd099b4f22d9": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Automation & AI Strategy", + "layout": "IPY_MODEL_d06eb8adf9994ae89d82f3983fdcf24f", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "AI driven by board pressure; no written thesis" + } + }, + "ef01e7fbeb1941ec8bfa0d387afe11fe": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "ef0dadfa61ff4ba0a581baac678f060c": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f0ead6ff95fd46d598e4b8cd15cce31d": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Evidence — Technical Architecture", + "layout": "IPY_MODEL_d885ae9c19e744248b31df0a37c3e498", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "CCaaS APIs available; shared integration layer WIP" + } + }, + "f13438fbf2ef4d08948f8abc7386c998": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "f24ef21b03f04b90aaad8349a7f2ce48": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f2ac82071dce4a89b8b98630090cd470": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f86046c7d0fb4a79bf086f572ae62e00": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "facdfdd6c0494307b51225d81b78aad8": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.number.NumberInputWidget", + "_css": "\n .mljar-number-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-number-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-number-field-row {\n display: flex;\n align-items: stretch;\n width: 100%;\n min-height: 40px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n .mljar-number-input {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100%;\n padding: 7px 10px;\n border: 0;\n border-radius: 0;\n background: #ffffff;\n box-sizing: border-box;\n background-color: #ffffff !important;\n color: #0f172a !important;\n font: inherit;\n line-height: 1.2;\n -moz-appearance: textfield;\n }\n\n .mljar-number-input::-webkit-outer-spin-button,\n .mljar-number-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n\n .mljar-number-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-number-input:focus {\n outline: none;\n }\n\n .mljar-number-field-row:focus-within {\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-number-field-row:focus-within .mljar-number-controls {\n border-left-color: #007bff;\n }\n\n .mljar-number-controls {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n border-left: 1px solid #cfd1d5;\n background: #f1f1f2;\n }\n\n .mljar-number-step-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 38px;\n min-width: 38px;\n min-height: 100%;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: #0f172a;\n font: inherit;\n font-size: 18px;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n padding: 0;\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-number-step-up {\n border-left: 1px solid #cfd1d5;\n }\n\n .mljar-number-step-btn:hover {\n background: #f3f3f4;\n }\n\n .mljar-number-step-btn:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:focus-visible {\n outline: none;\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-number-step-btn:disabled {\n background: #f5f5f5;\n color: #aaa;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-number-field-row {\n min-height: 44px;\n }\n\n .mljar-number-input {\n min-height: 44px;\n padding: 8px 12px;\n }\n\n .mljar-number-step-btn {\n font-size: 19px;\n width: 44px;\n min-width: 44px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-number-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-number-label\");\n\n const fieldRow = document.createElement(\"div\");\n fieldRow.classList.add(\"mljar-number-field-row\");\n\n const input = document.createElement(\"input\");\n input.type = \"number\";\n input.classList.add(\"mljar-number-input\");\n\n const decrementBtn = document.createElement(\"button\");\n decrementBtn.type = \"button\";\n decrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-down\");\n decrementBtn.textContent = \"-\";\n decrementBtn.setAttribute(\"aria-label\", \"Decrease value\");\n\n const incrementBtn = document.createElement(\"button\");\n incrementBtn.type = \"button\";\n incrementBtn.classList.add(\"mljar-number-step-btn\", \"mljar-number-step-up\");\n incrementBtn.textContent = \"+\";\n incrementBtn.setAttribute(\"aria-label\", \"Increase value\");\n\n const controls = document.createElement(\"div\");\n controls.classList.add(\"mljar-number-controls\");\n\n controls.appendChild(decrementBtn);\n controls.appendChild(incrementBtn);\n fieldRow.appendChild(input);\n fieldRow.appendChild(controls);\n\n container.appendChild(topLabel);\n container.appendChild(fieldRow);\n el.appendChild(container);\n\n function clamp(val, min, max) {\n if (Number.isFinite(min) && val < min) return min;\n if (Number.isFinite(max) && val > max) return max;\n return val;\n }\n\n function normalizeStep(step) {\n return Number.isFinite(step) && step > 0 ? step : 1;\n }\n\n function snapToStep(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = Math.round((value - base) / safeStep);\n const snapped = base + steps * safeStep;\n const precision = Math.max(\n 0,\n (String(safeStep).split(\".\")[1] || \"\").length\n );\n\n return Number(snapped.toFixed(precision + 2));\n }\n\n function isOnStepGrid(value, min, step) {\n const safeStep = normalizeStep(step);\n const base = Number.isFinite(min) ? min : 0;\n const steps = (value - base) / safeStep;\n const nearest = Math.round(steps);\n const epsilon = Math.max(1e-9, safeStep * 1e-9);\n\n return Math.abs(steps - nearest) <= epsilon;\n }\n\n function getCurrentBounds() {\n return {\n min: Number(model.get(\"min\")),\n max: Number(model.get(\"max\")),\n };\n }\n\n function isTransientDraft(raw) {\n return raw === \"\" || raw === \"-\" || raw === \".\" || raw === \"-.\";\n }\n\n let isEditing = false;\n const INPUT_COMMIT_DEBOUNCE_MS = 400;\n\n function clearPendingDraftCommit() {\n if (debounceTimer) clearTimeout(debounceTimer);\n pendingDraftValue = null;\n }\n\n function parseDraftValue(rawValue) {\n const raw = String(rawValue).trim();\n if (isTransientDraft(raw)) {\n return { kind: \"transient\" };\n }\n\n const value = Number(raw);\n if (!Number.isFinite(value)) {\n return { kind: \"invalid\" };\n }\n\n return { kind: \"number\", value };\n }\n\n function commitValue(nextValue, saveNow = true) {\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n const parsed = parseDraftValue(nextValue);\n if (parsed.kind !== \"number\") {\n syncFromModel();\n return;\n }\n\n let v = parsed.value;\n v = clamp(v, min, max);\n v = snapToStep(v, min, step);\n v = clamp(v, min, max);\n input.value = String(v);\n model.set(\"value\", v);\n\n if (saveNow) {\n model.save_changes();\n }\n }\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter number\";\n\n const min = Number(model.get(\"min\"));\n const max = Number(model.get(\"max\"));\n const step = Number(model.get(\"step\"));\n\n if (Number.isFinite(min)) input.min = String(min); else input.removeAttribute(\"min\");\n if (Number.isFinite(max)) input.max = String(max); else input.removeAttribute(\"max\");\n if (Number.isFinite(step)) input.step = String(step); else input.removeAttribute(\"step\");\n\n const v = Number(model.get(\"value\"));\n if (!isEditing) {\n input.value = Number.isFinite(v) ? String(v) : \"\";\n }\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n incrementBtn.disabled = disabled;\n decrementBtn.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n let debounceTimer = null;\n let pendingDraftValue = null;\n input.addEventListener(\"focus\", () => {\n isEditing = true;\n });\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n\n const parsed = parseDraftValue(input.value);\n if (parsed.kind !== \"number\") {\n clearPendingDraftCommit();\n return;\n }\n\n const v = parsed.value;\n const { min, max } = getCurrentBounds();\n const step = Number(model.get(\"step\"));\n if (Number.isFinite(min) && v < min) {\n clearPendingDraftCommit();\n return;\n }\n if (Number.isFinite(max) && v > max) {\n clearPendingDraftCommit();\n return;\n }\n if (!isOnStepGrid(v, min, step)) {\n clearPendingDraftCommit();\n return;\n }\n\n pendingDraftValue = v;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (pendingDraftValue === null) return;\n model.set(\"value\", pendingDraftValue);\n model.save_changes();\n pendingDraftValue = null;\n }, INPUT_COMMIT_DEBOUNCE_MS);\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n clearPendingDraftCommit();\n commitValue(input.value, true);\n });\n\n input.addEventListener(\"keydown\", event => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n input.blur();\n }\n });\n\n incrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base + step, min, step));\n });\n\n decrementBtn.addEventListener(\"click\", () => {\n if (model.get(\"disabled\")) return;\n const current = Number(model.get(\"value\"));\n const step = normalizeStep(Number(model.get(\"step\")));\n const min = Number(model.get(\"min\"));\n const base = Number.isFinite(current) ? current : 0;\n commitValue(snapToStep(base - step, min, step));\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:min\", syncFromModel);\n model.on(\"change:max\", syncFromModel);\n model.on(\"change:step\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }*/\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Agent headcount", + "layout": "IPY_MODEL_b4527b9783fe43598a8d5846ac38e606", + "layout_path": null, + "max": 100000.0, + "min": 0.0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "step": 10.0, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": 450.0 + } + }, + "fd25d64cd05848d7958943957f7bd4a8": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ff4373a0dfc347d09f933f0e101f3243": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Client name", + "layout": "IPY_MODEL_1e1189045b604913a5383ec4b05aff36", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Acme Demo Co" + } + } + }, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/studies/202607_CX_AI_Diagnostic/pyproject.toml b/studies/202607_CX_AI_Diagnostic/pyproject.toml new file mode 100644 index 0000000..8828850 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/pyproject.toml @@ -0,0 +1,38 @@ +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[project] +name = "diaglib" +version = "0.1.0" +description = "CX AI Advisory Diagnostic — facilitator's workshop cockpit (Mercury Notebook Pattern)" +requires-python = ">=3.11" +# The notebook is the deliverable (served with Mercury, exported via +# nbconvert, tables via tabulate) — the whole toolchain is a required +# runtime dependency, not an extra. `pip install -e .` must be enough. +dependencies = [ + "pandas>=2.0", + "plotly>=5.18", + "mercury>=3.2", + "jupyterlab>=4.0", + "ipywidgets>=8.0", + "nbconvert>=7", + "nbformat>=5.9", + "tabulate>=0.9", + "pydantic>=2.5", + "PyYAML>=6.0", +] + +[project.optional-dependencies] +dev = ["pytest>=7.4", "mypy>=1.8"] + +[tool.setuptools.packages.find] +include = ["diaglib*"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "-q" + +[tool.mypy] +strict = true +packages = ["diaglib"] diff --git a/studies/202607_CX_AI_Diagnostic/scripts/build_notebook.py b/studies/202607_CX_AI_Diagnostic/scripts/build_notebook.py new file mode 100644 index 0000000..0b93eb3 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/scripts/build_notebook.py @@ -0,0 +1,630 @@ +"""Generate notebooks/diagnostic.ipynb from source cell text. + +The diagnostic has ~50 Mercury widgets (engagement form, six baseline +inputs with confidence flags, 12 score sliders + 12 evidence fields, an +export button). Hand-maintaining that JSON is error-prone, so the +notebook is *generated* — cell sources live here as readable Python +strings and nbformat writes valid JSON. + +Re-run after editing any cell: python scripts/build_notebook.py +Then execute + export as usual (nbconvert / scripts/export_report.py). + +This is a build tool, not the engine — all study logic stays in diaglib. +""" + +from __future__ import annotations + +import pathlib + +import nbformat as nbf + +ROOT = pathlib.Path(__file__).resolve().parent.parent +OUT = ROOT / "notebooks" / "diagnostic.ipynb" + + +# ── Cell sources ───────────────────────────────────────────────────── + +MD_TITLE = """\ +# CX AI Advisory Diagnostic + +The facilitator's cockpit for the CX AI Advisory diagnostic workshop: +capture capability scores across **12 competencies** in four dimensions, +ingest the client's operational baseline, and watch the **value-at-stake +analysis** — bounded by the capability gaps — recompute live in the room. + +**This notebook is the deliverable.** Serve it with +`mercury --working-dir .` from the study root and share the screen. Work +the sidebar top-to-bottom: engagement, baseline, then one competency at a +time. The stage shows the current competency's card, the heatmap, the +value analysis, and the unlock sequence. Click **Export JSON + CSV** at +the bottom to write the structured engagement record to `exports/`. + +All content and math live in `diaglib/` and `configs/*.yaml` — the +notebook only arranges and renders them. Outputs are **ranges, never +point estimates**, and money displays at two significant figures. + +Confidence legend: 🟢 known · 🟡 estimated · 🔴 unknown — flag each +baseline input; unknowns surface as explicit warnings in the analysis.""" + + +SETUP = '''\ +# ── Setup ────────────────────────────────────────────────────────── +import sys, pathlib +_ROOT = pathlib.Path.cwd() +if not (_ROOT / "diaglib").exists(): # notebook lives in notebooks/ + _ROOT = _ROOT.parent +sys.path.insert(0, str(_ROOT)) + +import datetime as dt +import html as _html + +import mercury as mr +import pandas as pd +from IPython.display import display + +# Single source of truth — all math and content live in the library; +# only presentation (and Mercury widgets) lives here. +from diaglib import ( + BASELINE_FIELDS, CONFIDENCE_ICON, CSV_COLUMNS, + OperationalBaseline, backstage, build_engagement, build_scores, + configs_dir, dimension_rollup, engagement_json, evidence_coverage, + heatmap_fig, heatmap_grid, list_industries, load_config, money, + parse_participants, scores_dataframe, split_fig, unlock_fig, + value_at_stake, value_bands_fig, write_exports, +) + +pd.options.display.float_format = "{:,.0f}".format + +CONFIGS_DIR = configs_dir(_ROOT) +EXPORTS_DIR = _ROOT / "exports" +INDUSTRIES = list_industries(CONFIGS_DIR) +# The competency model is industry-independent (overlays may not redefine +# it — the loader enforces that), so widgets can build from any config. +_BASE = load_config("contact_center", CONFIGS_DIR) +COMPETENCIES = _BASE.competencies +DIMENSION_NAME = {d.id: d.name for d in _BASE.dimensions} + +# ── Brand palette (docs/brand.md, light theme) ───────────────────── +NAVY, INK, MUTED = "#151d2c", "#2e404d", "#586671" +BLUE, GREEN, LINE = "#0072bc", "#00a34c", "#e2e6e9" +CARD_BG, HAIRLINE, HILITE = "#f8f8f8", "#d5d9db", "#dcecfa" +FONT = "Georgia, 'Times New Roman', serif" +BODY_FONT = "Arial, 'Helvetica Neue', Helvetica, sans-serif" + + +def esc(s): + return _html.escape(str(s)) + + +# ── Workshop seeds — the gate's mock scenario; overwrite live ────── +# Headless nbconvert renders every widget at its seed, so the seeds form +# a coherent, gate-passing scenario (Pattern §3). +SEED_CLIENT = "Acme Demo Co" +SEED_DATE = "2026-07-19" +SEED_FACILITATOR = "Robert Helewka" +SEED_PARTICIPANTS = ("Jane Example | VP Customer Experience | cx; " + "Sam Sample | Contact Center Ops Director | ops") +SEED_BASELINE = { + "annual_contact_volume": 1_200_000, + "blended_cost_per_contact": 6.50, + "agent_headcount": 450, + "annual_attrition_rate": 0.30, + "current_containment_rate": 0.20, + "average_handle_time_seconds": 420, +} +CONFIDENCE_CHOICES = ["🟢 known", "🟡 estimated", "🔴 unknown"] +SEED_CONFIDENCE = { + "annual_contact_volume": "🟢 known", + "blended_cost_per_contact": "🟡 estimated", + "agent_headcount": "🟢 known", + "annual_attrition_rate": "🟡 estimated", + "current_containment_rate": "🟡 estimated", + "average_handle_time_seconds": "🟢 known", +} +# Seed capability profile: data_readiness is the unique weakest +# foundation, so the demo shows a single binding constraint. +SEED_SCORES = { + "automation_ai_strategy": (2, "AI driven by board pressure; no written thesis"), + "value_realization": (2, "Business cases pre-investment only"), + "executive_alignment": (3, "COO owns CX AI; steering meets quarterly"), + "process_discovery": (3, "Top 10 call reasons mapped with volumes"), + "data_readiness": (2, "KB stale; interaction data siloed in recordings"), + "technical_architecture": (3, "CCaaS APIs available; shared integration layer WIP"), + "use_case_prioritization": (3, "Scored backlog reviewed monthly"), + "delivery_capability": (3, "Two bots in production via SI partner"), + "talent_and_skills": (2, "One conversation designer, contractor"), + "ai_operations": (2, "Containment eyeballed weekly, no drift alerts"), + "change_adoption": (3, "Agent champions for copilot rollout"), + "governance_and_risk": (3, "AI policy signed; review board for voice bots"), +} +# label, min, max, step per baseline field (explicit min/max — Pattern §3). +BASELINE_META = { + "annual_contact_volume": ("Annual contact volume", 0, 100_000_000, 10_000), + "blended_cost_per_contact": ("Blended cost per contact ($)", 0, 100, 0.25), + "agent_headcount": ("Agent headcount", 0, 100_000, 10), + "annual_attrition_rate": ("Annual attrition rate (0-1)", 0, 1, 0.01), + "current_containment_rate": ("Current containment rate (0-1)", 0, 1, 0.01), + "average_handle_time_seconds": ("Average handle time (seconds)", 0, 3600, 10), +} + +backstage(f"diaglib loaded — {len(COMPETENCIES)} competencies · " + f"industries: {', '.join(INDUSTRIES)}")''' + + +MD_HOWTO = """\ +## How to run this session + +- **Sidebar §1 — Engagement.** Client, industry config, date, participants + (`Name | Role | Function` separated by `;` — functions: cx, it, ops, + finance, other), and a running notes box. +- **Sidebar §2 — Operational baseline.** Six numbers. If unknown, best + estimate is fine — set the confidence flag and the analysis will carry + the uncertainty explicitly. +- **Sidebar §3 — Capability scoring.** Pick **Now scoring**, read the + competency card on stage with the room, set the 1–5 slider, capture one + line of evidence, move to the next. The heatmap and value analysis + update live as you go. +- **Export.** The button at the bottom of the page writes + `exports/{engagement_id}.json` (source of truth) and `.csv` (flat + scores) — a deliberate snapshot at click time. +- **Backstage** (JupyterLab / nbconvert) — the verification gate and the + machine-readable appendix; neither shows on the Mercury stage.""" + + +W_ENGAGEMENT = '''\ +# ── 1 · Engagement setup (sidebar — widgets ONLY, no other output) ── +# Mercury re-runs only cells BELOW a changed widget: every .value is +# read in the state cell further down, never here (Pattern §3). +mr.Markdown("#### 1 · Engagement", position="sidebar") +_client_w = mr.TextInput(label="Client name", value=SEED_CLIENT) +_industry_w = mr.Select(label="Industry config", value="contact_center", + choices=INDUSTRIES) +_date_w = mr.DateInput(label="Workshop date", value=SEED_DATE) +_facilitator_w = mr.TextInput(label="Facilitator", value=SEED_FACILITATOR) +_participants_w = mr.TextInput( + label="Participants — Name | Role | Function; ...", + value=SEED_PARTICIPANTS) +_notes_w = mr.TextInput(label="Session notes", value="")''' + + +W_BASELINE = '''\ +# ── 2 · Operational baseline (sidebar — widgets ONLY) ─────────────── +# Six numbers + a confidence flag each. Explicit min/max on every +# NumberInput — Mercury clamps out-of-range seeds to a default range. +mr.Markdown("#### 2 · Operational baseline", position="sidebar") +_baseline_w, _conf_w = {}, {} +for _f in BASELINE_FIELDS: + _label, _min, _max, _step = BASELINE_META[_f] + _baseline_w[_f] = mr.NumberInput(label=_label, value=SEED_BASELINE[_f], + min=_min, max=_max, step=_step) + _conf_w[_f] = mr.Select(label=f"{_label} — confidence", + value=SEED_CONFIDENCE[_f], + choices=CONFIDENCE_CHOICES)''' + + +W_SCORING = '''\ +# ── 3 · Capability scoring (sidebar — widgets ONLY) ───────────────── +# One screen per competency on stage: pick "Now scoring", read the card +# with the room, set the slider, capture one line of evidence. Labels +# are distinct per widget so Mercury's cache never collides. +mr.Markdown("#### 3 · Capability scoring", position="sidebar") +_now_scoring_w = mr.Select( + label="Now scoring", + value=f"1 · {COMPETENCIES[0].name}", + choices=[f"{_i + 1} · {_c.name}" for _i, _c in enumerate(COMPETENCIES)]) +_score_w, _evidence_w = {}, {} +_prev_dim = None +for _c in COMPETENCIES: + if _c.dimension != _prev_dim: + mr.Markdown(f"**{DIMENSION_NAME[_c.dimension]}**", position="sidebar") + _prev_dim = _c.dimension + _score_w[_c.id] = mr.Slider(label=f"Score — {_c.name}", + min=1, max=5, value=SEED_SCORES[_c.id][0]) + _evidence_w[_c.id] = mr.TextInput(label=f"Evidence — {_c.name}", + value=SEED_SCORES[_c.id][1])''' + + +STATE = '''\ +# ── Session state (re-runs on any sidebar change) ─────────────────── +# Read every widget .value; all computation happens in diaglib. +CLIENT_NAME = str(_client_w.value).strip() or SEED_CLIENT +INDUSTRY = str(_industry_w.value) +CONFIG = load_config(INDUSTRY, CONFIGS_DIR) +WORKSHOP_DATE = dt.date.fromisoformat(str(_date_w.value) or SEED_DATE) +PARTICIPANTS = parse_participants(str(_participants_w.value)) +NOTES = str(_notes_w.value) + +_vals = {f: float(_baseline_w[f].value) for f in BASELINE_FIELDS} +BASELINE = OperationalBaseline( + annual_contact_volume=int(_vals["annual_contact_volume"]), + blended_cost_per_contact=_vals["blended_cost_per_contact"], + agent_headcount=int(_vals["agent_headcount"]), + annual_attrition_rate=_vals["annual_attrition_rate"], + current_containment_rate=_vals["current_containment_rate"], + average_handle_time_seconds=int(_vals["average_handle_time_seconds"]), + field_confidence={f: str(_conf_w[f].value).split()[-1] + for f in BASELINE_FIELDS}, +) + +RAW_SCORES = {c.id: (int(_score_w[c.id].value), str(_evidence_w[c.id].value)) + for c in COMPETENCIES} +SCORES = build_scores(CONFIG, RAW_SCORES, scored_at=dt.datetime.now()) +VAS = value_at_stake(CONFIG, BASELINE, SCORES) +ENGAGEMENT = build_engagement( + config=CONFIG, client_name=CLIENT_NAME, + facilitator=str(_facilitator_w.value), workshop_date=WORKSHOP_DATE, + participants=PARTICIPANTS, baseline=BASELINE, scores=SCORES, + computed_value=VAS, notes=NOTES) + +NOW_SCORING = COMPETENCIES[int(str(_now_scoring_w.value).split(" · ")[0]) - 1] +_done, _total = evidence_coverage(SCORES) + +# One curated line on stage; warnings surface for the room; echo backstage. +if CONFIG.value_drivers: + _bind = ", ".join(CONFIG.competency(c).name for c in VAS.binding_constraints) + print(f"Value at stake: {money(VAS.theoretical_annual_value_low)}-" + f"{money(VAS.theoretical_annual_value_high)} theoretical per year · " + f"{money(VAS.realizable_18mo_low)}-{money(VAS.realizable_18mo_high)} " + f"realizable over 18 months — capped at level " + f"{VAS.weakest_foundational_score} by {_bind}") +for _warning in VAS.warnings: + print(f"⚠ {_warning}") +backstage(f"engagement {ENGAGEMENT.engagement_id} · " + f"{len(PARTICIPANTS)} participants · evidence {_done}/{_total}")''' + + +STAGE_HEADER = '''\ +# ── Stage: engagement banner + baseline echo ──────────────────────── +_chips = "".join( + f'{esc(p.name)}' + + (f" · {esc(p.role)}" if p.role else "") + + f' {esc(p.function)}' + for p in PARTICIPANTS) or ( + f'' + f'no participants captured yet') + +_rows = "" +for _f in BASELINE_FIELDS: + _v = getattr(BASELINE, _f) + _shown = f"{_v:,.2f}" if isinstance(_v, float) and _v < 10 else f"{_v:,.0f}" + _rows += ( + f'{BASELINE_META[_f][0]}' + f'{_shown}' + f'{CONFIDENCE_ICON[BASELINE.confidence_for(_f)]}' + f'') + +_ = mr.Markdown(text=( + f'
' + f'
' + f'{esc(CLIENT_NAME)} — CX AI Diagnostic
' + f'
' + f'{esc(CONFIG.display_name)} · {WORKSHOP_DATE.isoformat()} · ' + f'facilitated by {esc(ENGAGEMENT.facilitator)} · ' + f'evidence captured {_done}/{_total}
' + f'
{_chips}
' + f'
' + f'
' + f'Operational baseline
' + f'{_rows}
'))''' + + +STAGE_CARD = '''\ +# ── Stage: the scoring screen (one competency at a time) ──────────── +_c = NOW_SCORING +_score, _evidence = RAW_SCORES[_c.id] + +# Progress strip: one box per competency — its current score, solid +# border once evidence is captured, highlighted while on screen. +_boxes = "" +for _i, _cc in enumerate(COMPETENCIES): + _s, _e = RAW_SCORES[_cc.id] + _bg = HILITE if _cc.id == _c.id else CARD_BG + _border = f"1px solid {HAIRLINE}" if not _e else f"1px solid {MUTED}" + if _cc.id == _c.id: + _border = f"2px solid {BLUE}" + _boxes += ( + f'{_s}') + +_levels = "" +for _lvl in range(1, 6): + _sel = _lvl == _score + _levels += ( + f'{_lvl}' + f'' + f'{esc(_c.level_descriptors[_lvl])}') + +_evidence_html = ( + f' {esc(_evidence)}' if _evidence + else f'no evidence captured yet — ' + f'one line: what makes this a level {_score}?') + +_ = mr.Markdown(text=( + f'
' + f'
{_boxes}
' + f'
' + f'
' + f'{DIMENSION_NAME[_c.dimension]}
' + f'
' + f'{esc(_c.name)}
' + f'
' + f'{esc(_c.description)}
' + f'
' + f'"{esc(_c.failure_vignette)}"
' + f'{_levels}
' + f'
' + f'Evidence: {_evidence_html}
' + f'
'))''' + + +STAGE_ANALYSIS = '''\ +# ── Stage: live analysis & visuals ────────────────────────────────── +heatmap_fig(heatmap_grid(CONFIG, SCORES)).show() + +if CONFIG.value_drivers: + value_bands_fig(VAS).show() + split_fig(VAS).show() + unlock_fig(VAS, CONFIG).show() + # The unlock moves as a table — the room verifies numbers by + # reading them, not by trusting the bars. + UNLOCK_DF = pd.DataFrame([{ + "Move": _i + 1, + "Competencies": " + ".join(CONFIG.competency(c).name + for c in _m.competency_ids), + "Lift": f"{_m.current_level} → {_m.target_level}", + "Est. cost": (f"{money(_m.est_cost_low)} – {money(_m.est_cost_high)}" + if _m.est_cost_low is not None else "not configured"), + "Weeks": _m.est_weeks if _m.est_weeks is not None else "—", + "Annual value unlocked": (f"{money(_m.value_unlocked_low)} – " + f"{money(_m.value_unlocked_high)}"), + "Note": _m.note, + } for _i, _m in enumerate(VAS.unlock_sequence)]) + display(UNLOCK_DF.style.hide(axis="index")) +else: + _ = mr.Markdown(text=( + f'
' + f'{esc(CONFIG.display_name)} has no value ' + f'drivers configured yet — capability scoring works normally, but ' + f'value-at-stake needs drivers in ' + f'configs/{esc(INDUSTRY)}.yaml.
'))''' + + +MD_EXPORT = """\ +## Export + +The button writes `exports/{engagement_id}.json` — the full engagement +record, the source-of-truth artifact — and `exports/{engagement_id}.csv`, +one row per competency for cross-engagement analysis. A **deliberate +snapshot**: it captures the state at click time; click again after +changes to refresh.""" + + +W_EXPORT = '''\ +# ── Export trigger (widgets ONLY — the click is handled below) ────── +_export_w = mr.Button(label="Export JSON + CSV", position="inline")''' + + +EXPORT_STATE = '''\ +# ── Export on click — snapshot semantics ──────────────────────────── +# Kernel globals persist across Mercury re-runs; the guard writes +# exactly once per click, at whatever state the cockpit showed then. +try: + _LAST_EXPORT_CLICKS +except NameError: + _LAST_EXPORT_CLICKS = 0 + +if int(_export_w.n_clicks) > _LAST_EXPORT_CLICKS: + _json_path, _csv_path = write_exports(ENGAGEMENT, CONFIG, EXPORTS_DIR) + _LAST_EXPORT_CLICKS = int(_export_w.n_clicks) + print(f"Exported {_json_path.name} + {_csv_path.name} → exports/") +else: + backstage("No export click this run — engagement exports come from the " + "stage button; report sources from scripts/export_report.py.")''' + + +MD_GATE = """\ +## Verification & assertions + +Engine pins use the explicit seed scenario, independent of the sidebar, +so the gate tests `diaglib` + `configs/`, not the current session; +live-state pins are guarded so a facilitator moving a slider never +crashes the room; structural ties hold at **any** widget state. This +cell must pass under headless `nbconvert --execute` — it is the study's +smoke test. Output renders backstage only.""" + + +GATE = '''\ +# ── Verification gate — must pass under headless nbconvert ────────── +def _approx(got, want, tol=0.5): + assert abs(got - want) <= tol, f"got {got:,.2f}, want {want:,.2f}" + + +# Engine pins — EXPLICIT seed scenario, independent of widget state. +# Hand arithmetic in tests/test_value_math.py (same scenario). +_gate_cfg = load_config("contact_center", CONFIGS_DIR) +_gate_baseline = OperationalBaseline( + annual_contact_volume=1_200_000, blended_cost_per_contact=6.50, + agent_headcount=450, annual_attrition_rate=0.30, + current_containment_rate=0.20, average_handle_time_seconds=420) +_gate_scores = build_scores(_gate_cfg, SEED_SCORES, + scored_at=dt.datetime(2026, 7, 19, 9, 0)) +_gate_vas = value_at_stake(_gate_cfg, _gate_baseline, _gate_scores) +_approx(_gate_vas.theoretical_annual_value_low, 2_542_500) +_approx(_gate_vas.theoretical_annual_value_high, 5_085_000) +_approx(_gate_vas.realizable_18mo_low, 953_437.50) +_approx(_gate_vas.realizable_18mo_high, 3_051_000) +_approx(_gate_vas.trapped_value_low, 1_525_500) +_approx(_gate_vas.trapped_value_high, 3_813_750) +assert _gate_vas.binding_constraints == ["data_readiness"] +assert len(_gate_vas.unlock_sequence) == 3 +_m1 = _gate_vas.unlock_sequence[0] +assert _m1.competency_ids == ["data_readiness"] +assert (_m1.est_cost_low, _m1.est_cost_high, _m1.est_weeks) == (300_000, 600_000, 12) +_approx(_m1.value_unlocked_low, 635_625) +_approx(_m1.value_unlocked_high, 1_271_250) + +# Live-state pins — guarded, so a moved slider can't crash the room. +_at_default = ( + INDUSTRY == "contact_center" + and all(getattr(BASELINE, f) == getattr(_gate_baseline, f) + for f in BASELINE_FIELDS) + and all(RAW_SCORES[k][0] == SEED_SCORES[k][0] for k in SEED_SCORES)) +if _at_default: + _approx(VAS.theoretical_annual_value_low, 2_542_500) + _approx(VAS.realizable_18mo_high, 3_051_000) + _approx(VAS.trapped_value_high, 3_813_750) + +# Structural ties — hold at ANY widget state. +assert len(SCORES) == 12 and len({s.competency_id for s in SCORES}) == 12 +assert VAS.theoretical_annual_value_low <= VAS.theoretical_annual_value_high +assert VAS.realizable_18mo_low <= VAS.realizable_18mo_high +assert VAS.trapped_value_low <= VAS.trapped_value_high +_approx(sum(d.theoretical_low for d in VAS.driver_values), + VAS.theoretical_annual_value_low) +_approx(sum(d.theoretical_high for d in VAS.driver_values), + VAS.theoretical_annual_value_high) +_approx(VAS.realizable_18mo_low, + VAS.theoretical_annual_value_low * VAS.realization_factor_low * 1.5) +_approx(VAS.realizable_18mo_high, + VAS.theoretical_annual_value_high * VAS.realization_factor_high * 1.5) +assert set(VAS.binding_constraints) <= set(CONFIG.foundational_competencies) +assert len(VAS.unlock_sequence) <= 3 + +# Export payload is serializable and matches the live session. +import json as _json +_payload = _json.loads(engagement_json(ENGAGEMENT)) +assert _payload["engagement_id"] == ENGAGEMENT.engagement_id +assert len(_payload["scores"]) == 12 +_df = scores_dataframe(ENGAGEMENT, CONFIG) +assert list(_df.columns) == CSV_COLUMNS and len(_df) == 12 + +backstage("All assertions passed.")''' + + +MD_APPENDIX = """\ +## Data appendix — for the machines + +The full engagement as markdown tables plus one JSON block of state, so +the exported report is complete LLM input — and the future Athena +study-export payload. Renders **backstage** — hidden on the Mercury +stage.""" + + +APPENDIX = '''\ +# ── Data appendix — LLM-readable dump of the engagement ───────────── +# Renders backstage only (JupyterLab / nbconvert exports). +backstage("#### Capability scores\\n") +_rows = ["| Competency | Dimension | Score | Evidence |", "|---|---|---:|---|"] +for _s in SCORES: + _cc = CONFIG.competency(_s.competency_id) + _ev = _s.evidence.replace("|", "\\\\|") or "—" + _rows.append(f"| {_cc.name} | {DIMENSION_NAME[_s.dimension]} | " + f"{_s.score} | {_ev} |") +backstage("\\n".join(_rows)) + +backstage("\\n#### Dimension rollup\\n") +_rows = ["| Dimension | Mean score |", "|---|---:|"] +for _did, _dname, _mean in dimension_rollup(CONFIG, SCORES): + _rows.append(f"| {_dname} | {_mean:.2f} |") +backstage("\\n".join(_rows)) + +if CONFIG.value_drivers: + backstage("\\n#### Value drivers (theoretical annual)\\n") + _rows = ["| Driver | Low | High |", "|---|---:|---:|"] + for _d in VAS.driver_values: + _rows.append(f"| {_d.name} | {money(_d.theoretical_low)} | " + f"{money(_d.theoretical_high)} |") + _rows.append(f"| **Total** | **{money(VAS.theoretical_annual_value_low)}** " + f"| **{money(VAS.theoretical_annual_value_high)}** |") + backstage("\\n".join(_rows)) + backstage(f"\\nRealization band at weakest foundation level " + f"{VAS.weakest_foundational_score}: " + f"{VAS.realization_factor_low:.0%}-{VAS.realization_factor_high:.0%} · " + f"realizable 18-mo {money(VAS.realizable_18mo_low)}-" + f"{money(VAS.realizable_18mo_high)} · trapped " + f"{money(VAS.trapped_value_low)}-{money(VAS.trapped_value_high)} " + f"per year · binding: {', '.join(VAS.binding_constraints)}") + +backstage("\\n#### Engagement state (JSON)\\n") +backstage("```json") +backstage(engagement_json(ENGAGEMENT)) +backstage("```")''' + + +REVIEW = '''\ +# ── Review a saved engagement (backstage utility, optional) ───────── +# Point _REVIEW_JSON at an exports/*.json and run in JupyterLab to +# reload a past engagement for review; the live session is untouched. +_REVIEW_JSON = "" +if _REVIEW_JSON: + from diaglib import load_engagement + _prev = load_engagement(pathlib.Path(_REVIEW_JSON)) + backstage(f"loaded {_prev.engagement_id}: {_prev.client_name} · " + f"{len(_prev.scores)} scores · " + ( + "binding: " + ", ".join(_prev.computed_value.binding_constraints) + if _prev.computed_value else "no computed value"))''' + + +def md(source: str) -> nbf.NotebookNode: + return nbf.v4.new_markdown_cell(source) + + +def code(source: str) -> nbf.NotebookNode: + return nbf.v4.new_code_cell(source) + + +def build() -> nbf.NotebookNode: + nb = nbf.v4.new_notebook() + nb.cells = [ + md(MD_TITLE), + code(SETUP), + md(MD_HOWTO), + code(W_ENGAGEMENT), + code(W_BASELINE), + code(W_SCORING), + code(STATE), + code(STAGE_HEADER), + code(STAGE_CARD), + code(STAGE_ANALYSIS), + md(MD_EXPORT), + code(W_EXPORT), + code(EXPORT_STATE), + md(MD_GATE), + code(GATE), + md(MD_APPENDIX), + code(APPENDIX), + code(REVIEW), + ] + nb.metadata = { + "kernelspec": {"display_name": "Python 3", "language": "python", + "name": "python3"}, + "language_info": {"name": "python"}, + } + return nb + + +def main() -> None: + OUT.parent.mkdir(parents=True, exist_ok=True) + nbf.write(build(), OUT) + print(f"wrote {OUT.relative_to(ROOT)} ({len(build().cells)} cells)") + + +if __name__ == "__main__": + main() diff --git a/studies/202607_CX_AI_Diagnostic/scripts/export_report.py b/studies/202607_CX_AI_Diagnostic/scripts/export_report.py new file mode 100644 index 0000000..95985e2 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/scripts/export_report.py @@ -0,0 +1,47 @@ +"""Export the deliverable notebook as LLM-readable report sources. + +Executes the notebook fresh (widget seeds — the mock scenario, or +whatever seeds you edit in), then writes both formats to exports/: + + exports/diagnostic.html — human-reviewable, tables render + exports/diagnostic.md — leanest LLM input + +Plotly figures export as JavaScript an LLM cannot read; the notebook's +machine-readable appendix section carries every number behind them. + +Run from the project root: python scripts/export_report.py [name-filter] +An optional argument exports only notebooks whose filename contains it. +""" +from __future__ import annotations + +import subprocess +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +NOTEBOOKS = [ + ROOT / "notebooks" / "diagnostic.ipynb", +] +EXPORTS = ROOT / "exports" + + +def main() -> None: + picked = [nb for nb in NOTEBOOKS + if len(sys.argv) < 2 or sys.argv[1] in nb.name] + if not picked: + sys.exit(f"no notebook matches {sys.argv[1]!r}") + EXPORTS.mkdir(exist_ok=True) + for nb in picked: + for fmt in ("html", "markdown"): + subprocess.run( + [sys.executable, "-m", "nbconvert", "--execute", + "--to", fmt, "--output-dir", str(EXPORTS), str(nb)], + check=True, cwd=ROOT, + ) + for p in sorted(EXPORTS.iterdir()): + if p.suffix in (".html", ".md"): + print(f"wrote {p.relative_to(ROOT)} ({p.stat().st_size / 1024:,.0f} KB)") + + +if __name__ == "__main__": + main() diff --git a/studies/202607_CX_AI_Diagnostic/tests/conftest.py b/studies/202607_CX_AI_Diagnostic/tests/conftest.py new file mode 100644 index 0000000..91a3471 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/tests/conftest.py @@ -0,0 +1,70 @@ +"""Shared fixtures: the mock workshop scenario every pin is hand-checked +against (see test_value_math for the arithmetic). Also makes diaglib +importable without the study venv active (normal setup is +``pip install -e ".[dev]"`` into the study-local ``.venv/``).""" + +import pathlib +import sys +from datetime import datetime + +import pytest + +sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent)) + +from diaglib import OperationalBaseline, build_scores, load_config # noqa: E402 + +CONFIGS = pathlib.Path(__file__).resolve().parent.parent / "configs" + +SCORED_AT = datetime(2026, 7, 19, 9, 0) + +#: The seed capability profile: data_readiness is the unique weakest +#: foundation (level 2), so the binding constraint is a single competency. +SEED_SCORES = { + "automation_ai_strategy": (2, "AI driven by board pressure; no written thesis"), + "value_realization": (2, "Business cases pre-investment only"), + "executive_alignment": (3, "COO owns CX AI; steering meets quarterly"), + "process_discovery": (3, "Top 10 call reasons mapped with volumes"), + "data_readiness": (2, "KB stale; interaction data siloed in recordings"), + "technical_architecture": (3, "CCaaS APIs available; shared integration layer WIP"), + "use_case_prioritization": (3, "Scored backlog reviewed monthly"), + "delivery_capability": (3, "Two bots in production via SI partner"), + "talent_and_skills": (2, "One conversation designer, contractor"), + "ai_operations": (2, "Containment eyeballed weekly, no drift alerts"), + "change_adoption": (3, "Agent champions for copilot rollout"), + "governance_and_risk": (3, "AI policy signed; review board for voice bots"), +} + + +@pytest.fixture(scope="session") +def config(): + return load_config("contact_center", CONFIGS) + + +@pytest.fixture(scope="session") +def stub_config(): + return load_config("financial_services", CONFIGS) + + +@pytest.fixture() +def baseline(): + return OperationalBaseline( + annual_contact_volume=1_200_000, + blended_cost_per_contact=6.50, + agent_headcount=450, + annual_attrition_rate=0.30, + current_containment_rate=0.20, + average_handle_time_seconds=420, + field_confidence={ + "annual_contact_volume": "known", + "blended_cost_per_contact": "estimated", + "agent_headcount": "known", + "annual_attrition_rate": "estimated", + "current_containment_rate": "estimated", + "average_handle_time_seconds": "known", + }, + ) + + +@pytest.fixture() +def scores(config): + return build_scores(config, SEED_SCORES, scored_at=SCORED_AT) diff --git a/studies/202607_CX_AI_Diagnostic/tests/test_config.py b/studies/202607_CX_AI_Diagnostic/tests/test_config.py new file mode 100644 index 0000000..3b50fc5 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/tests/test_config.py @@ -0,0 +1,73 @@ +"""Config loading and validation — the instrument's shape can't drift.""" + +import shutil + +import pytest + +from diaglib import list_industries, load_config +from tests.conftest import CONFIGS + + +def test_contact_center_loads(config): + assert config.industry == "contact_center" + assert config.version == "1.0" + assert len(config.competencies) == 12 + assert [d.id for d in config.dimensions] == [ + "strategy_value", "foundations", "delivery", "sustain"] + # 4 dimensions × 3 competencies — the heatmap contract + for d in config.dimensions: + assert sum(1 for c in config.competencies if c.dimension == d.id) == 3 + assert config.foundational_competencies == [ + "process_discovery", "data_readiness", "technical_architecture"] + assert [d.id for d in config.value_drivers] == [ + "deflection_lift", "aht_reduction", "attrition_reduction"] + + +def test_capping_bands_pinned(config): + bands = {k: (v.realized_low, v.realized_high) + for k, v in config.capping_heuristic.items()} + assert bands == { + 1: (0.00, 0.15), 2: (0.25, 0.40), 3: (0.50, 0.65), + 4: (0.65, 0.85), 5: (0.80, 1.00), + } + + +def test_every_competency_has_five_levels_and_vignette(config): + for c in config.competencies: + assert set(c.level_descriptors) == {1, 2, 3, 4, 5} + assert c.failure_vignette + assert c.description + + +def test_unlock_costs_reachable(config): + # Every foundational competency can be lifted 1→5 in the CC config. + for cid in config.foundational_competencies: + for level in (1, 2, 3, 4): + lift = config.lift_cost(cid, level) + assert lift is not None, f"{cid} lift {level}->{level + 1} missing" + assert lift.cost_low <= lift.cost_high + + +def test_stub_config_loads(stub_config): + assert stub_config.industry == "financial_services" + assert stub_config.value_drivers == [] + assert len(stub_config.competencies) == 12 # model comes from base + + +def test_list_industries(): + assert list_industries(CONFIGS) == ["contact_center", "financial_services"] + + +def test_overlay_may_not_redefine_base_keys(tmp_path): + shutil.copy(CONFIGS / "base.yaml", tmp_path / "base.yaml") + (tmp_path / "rogue.yaml").write_text( + "extends: base\nindustry: rogue\ncompetencies: []\n", encoding="utf-8") + with pytest.raises(ValueError, match="base-only"): + load_config("rogue", tmp_path) + + +def test_overlay_must_extend_base(tmp_path): + shutil.copy(CONFIGS / "base.yaml", tmp_path / "base.yaml") + (tmp_path / "loner.yaml").write_text("industry: loner\n", encoding="utf-8") + with pytest.raises(ValueError, match="extends"): + load_config("loner", tmp_path) diff --git a/studies/202607_CX_AI_Diagnostic/tests/test_export.py b/studies/202607_CX_AI_Diagnostic/tests/test_export.py new file mode 100644 index 0000000..d73849d --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/tests/test_export.py @@ -0,0 +1,52 @@ +"""Export contracts — JSON round-trips, CSV shape pinned to the spec.""" + +from datetime import date + +import pandas as pd + +from diaglib import ( + CSV_COLUMNS, + build_engagement, + load_engagement, + parse_participants, + scores_dataframe, + value_at_stake, + write_exports, +) + + +def _engagement(config, baseline, scores): + return build_engagement( + config=config, client_name="Acme Demo Co", facilitator="Robert Helewka", + workshop_date=date(2026, 7, 19), + participants=parse_participants( + "Jane Example | VP Customer Experience | cx; Sam Sample | Ops Director | ops"), + baseline=baseline, scores=scores, + computed_value=value_at_stake(config, baseline, scores)) + + +def test_write_exports_and_reload(config, baseline, scores, tmp_path): + eng = _engagement(config, baseline, scores) + json_path, csv_path = write_exports(eng, config, tmp_path) + assert json_path.name == "acme_demo_co_2026-07-19.json" + assert csv_path.name == "acme_demo_co_2026-07-19.csv" + + # JSON is the source-of-truth artifact — it must round-trip losslessly. + reloaded = load_engagement(json_path) + assert reloaded == eng + + df = pd.read_csv(csv_path) + assert list(df.columns) == CSV_COLUMNS + assert len(df) == 12 + + +def test_scores_dataframe_flags(config, baseline, scores): + df = scores_dataframe(_engagement(config, baseline, scores), config) + by_id = df.set_index("competency_id") + assert bool(by_id.loc["data_readiness", "is_foundational"]) + assert bool(by_id.loc["data_readiness", "is_binding_constraint"]) + assert bool(by_id.loc["process_discovery", "is_foundational"]) + assert not bool(by_id.loc["process_discovery", "is_binding_constraint"]) + assert not bool(by_id.loc["automation_ai_strategy", "is_foundational"]) + assert (df["engagement_id"] == "acme_demo_co_2026-07-19").all() + assert (df["industry"] == "contact_center").all() diff --git a/studies/202607_CX_AI_Diagnostic/tests/test_scoring.py b/studies/202607_CX_AI_Diagnostic/tests/test_scoring.py new file mode 100644 index 0000000..631db39 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/tests/test_scoring.py @@ -0,0 +1,85 @@ +"""Scoring, parsing, and assembly — the glue the notebook leans on.""" + +from datetime import date + +import pytest + +from diaglib import ( + build_engagement, + build_scores, + dimension_rollup, + evidence_coverage, + heatmap_grid, + make_engagement_id, + parse_participants, + value_at_stake, +) +from tests.conftest import SCORED_AT, SEED_SCORES + +approx = pytest.approx + + +def test_engagement_id_slug(): + assert make_engagement_id("Acme", date(2026, 7, 19)) == "acme_2026-07-19" + assert make_engagement_id(" Acme & Söhne GmbH! ", + date(2026, 7, 19)) == "acme_s_hne_gmbh_2026-07-19" + assert make_engagement_id("", date(2026, 7, 19)) == "client_2026-07-19" + + +def test_parse_participants_forgiving(): + got = parse_participants( + "Jane Example | VP Customer Experience | cx; " + "Raj Patel|CIO|IT; Sam Sample | Ops Director; Solo") + assert [(p.name, p.role, p.function) for p in got] == [ + ("Jane Example", "VP Customer Experience", "cx"), + ("Raj Patel", "CIO", "it"), # case-normalized + ("Sam Sample", "Ops Director", "other"), # function missing + ("Solo", "", "other"), + ] + assert parse_participants("") == [] + assert parse_participants(" ; ; ") == [] + + +def test_build_scores_orders_and_validates(config): + scores = build_scores(config, SEED_SCORES, scored_at=SCORED_AT) + assert [s.competency_id for s in scores] == [c.id for c in config.competencies] + assert all(s.scored_at == SCORED_AT for s in scores) + with pytest.raises(ValueError, match="unscored"): + build_scores(config, {"data_readiness": (3, "")}, scored_at=SCORED_AT) + + +def test_dimension_rollup_pins(config, scores): + rollup = {dim_id: mean for dim_id, _, mean in dimension_rollup(config, scores)} + assert rollup["strategy_value"] == approx((2 + 2 + 3) / 3) + assert rollup["foundations"] == approx((3 + 2 + 3) / 3) + assert rollup["delivery"] == approx((3 + 3 + 2) / 3) + assert rollup["sustain"] == approx((2 + 3 + 3) / 3) + + +def test_evidence_coverage(config, scores): + assert evidence_coverage(scores) == (12, 12) # fixture captures all evidence + blank = [s.model_copy(update={"evidence": ""}) for s in scores[:3]] + scores[3:] + assert evidence_coverage(blank) == (9, 12) + + +def test_heatmap_grid_shape(config, scores): + grid = heatmap_grid(config, scores) + assert grid["rows"] == ["Strategy & Value", "Foundations", "Delivery", "Sustain"] + assert [len(r) for r in grid["z"]] == [3, 3, 3, 3] + assert grid["z"][1] == [3, 2, 3] # foundations row: pd, dr, ta + assert "Data Readiness" in grid["text"][1][1] + assert "KB stale" in grid["hover"][1][1] # evidence surfaces on hover + + +def test_build_engagement_assembles(config, baseline, scores): + vas = value_at_stake(config, baseline, scores) + eng = build_engagement( + config=config, client_name="Acme Demo Co", facilitator="Robert Helewka", + workshop_date=date(2026, 7, 19), + participants=parse_participants("Jane Example | VP CX | cx"), + baseline=baseline, scores=scores, computed_value=vas, + notes="dry run") + assert eng.engagement_id == "acme_demo_co_2026-07-19" + assert eng.industry_config == "contact_center" + assert len(eng.scores) == 12 + assert eng.computed_value.binding_constraints == ["data_readiness"] diff --git a/studies/202607_CX_AI_Diagnostic/tests/test_staging.py b/studies/202607_CX_AI_Diagnostic/tests/test_staging.py new file mode 100644 index 0000000..4174819 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/tests/test_staging.py @@ -0,0 +1,15 @@ +"""Stage/backstage detection — Mercury kernels carry MERCURY_CONFIG_DIR.""" + +from diaglib import staging + + +def test_backstage_prints_only_off_stage(monkeypatch, capsys): + monkeypatch.delenv("MERCURY_CONFIG_DIR", raising=False) + assert not staging.on_stage() + staging.backstage("visible") + assert capsys.readouterr().out == "visible\n" + + monkeypatch.setenv("MERCURY_CONFIG_DIR", "/tmp/app") + assert staging.on_stage() + staging.backstage("hidden") + assert capsys.readouterr().out == "" diff --git a/studies/202607_CX_AI_Diagnostic/tests/test_value_math.py b/studies/202607_CX_AI_Diagnostic/tests/test_value_math.py new file mode 100644 index 0000000..b62ced9 --- /dev/null +++ b/studies/202607_CX_AI_Diagnostic/tests/test_value_math.py @@ -0,0 +1,145 @@ +"""Value-math pins — every number hand-checked before pinning. + +Mock scenario (the notebook's widget seeds use the same values): + + volume 1,200,000 · $6.50/contact · 450 agents · 30% attrition · + 20% containment · 420s AHT · weakest foundation = data_readiness @ 2 + +Hand arithmetic: + + deflection low 1.2M × 0.15 × 6.50 = 1,170,000 high ×0.35 = 2,730,000 + AHT low 1.2M × 6.50 × 0.15 = 1,170,000 high ×0.25 = 1,950,000 + attrition low 450 × 0.30 × 0.10 × 15,000 = 202,500 high ×0.20 = 405,000 + theoretical low 2,542,500 high 5,085,000 + band @2 = (0.25, 0.40) + realizable 18mo low 2,542,500 × 0.25 × 1.5 = 953,437.50 + high 5,085,000 × 0.40 × 1.5 = 3,051,000 + trapped (annual) low 2,542,500 × (1−0.40) = 1,525,500 + high 5,085,000 × (1−0.25) = 3,813,750 +""" + +import pytest + +from diaglib import ( + binding_constraints, + driver_value, + money, + value_at_stake, + weakest_foundational_score, +) + +approx = pytest.approx + + +def test_driver_pins(config, baseline): + by_id = {d.id: driver_value(d, baseline) for d in config.value_drivers} + assert by_id["deflection_lift"].theoretical_low == approx(1_170_000) + assert by_id["deflection_lift"].theoretical_high == approx(2_730_000) + assert by_id["aht_reduction"].theoretical_low == approx(1_170_000) + assert by_id["aht_reduction"].theoretical_high == approx(1_950_000) + assert by_id["attrition_reduction"].theoretical_low == approx(202_500) + assert by_id["attrition_reduction"].theoretical_high == approx(405_000) + + +def test_value_at_stake_pins(config, baseline, scores): + vas = value_at_stake(config, baseline, scores) + assert vas.theoretical_annual_value_low == approx(2_542_500) + assert vas.theoretical_annual_value_high == approx(5_085_000) + assert vas.weakest_foundational_score == 2 + assert (vas.realization_factor_low, vas.realization_factor_high) == (0.25, 0.40) + assert vas.realizable_18mo_low == approx(953_437.50) + assert vas.realizable_18mo_high == approx(3_051_000) + assert vas.trapped_value_low == approx(1_525_500) + assert vas.trapped_value_high == approx(3_813_750) + assert vas.binding_constraints == ["data_readiness"] + assert vas.warnings == [] # nothing flagged unknown in the fixture + + +def test_unlock_sequence_pins(config, baseline, scores): + vas = value_at_stake(config, baseline, scores) + m1, m2, m3 = vas.unlock_sequence + + # Move 1 — the unique weakest foundation lifts alone. + assert m1.competency_ids == ["data_readiness"] + assert (m1.current_level, m1.target_level) == (2, 3) + assert (m1.est_cost_low, m1.est_cost_high, m1.est_weeks) == (300_000, 600_000, 12) + assert m1.value_unlocked_low == approx(2_542_500 * 0.25) # 635,625 + assert m1.value_unlocked_high == approx(5_085_000 * 0.25) # 1,271,250 + + # Move 2 — all three foundations now tie at 3: joint lift. + assert m2.competency_ids == [ + "process_discovery", "data_readiness", "technical_architecture"] + assert (m2.current_level, m2.target_level) == (3, 4) + assert m2.est_cost_low == approx(150_000 + 400_000 + 250_000) # 800,000 + assert m2.est_cost_high == approx(300_000 + 800_000 + 500_000) # 1,600,000 + assert m2.est_weeks == 16 # longest workstream + assert m2.value_unlocked_low == approx(2_542_500 * 0.15) # 381,375 + assert m2.value_unlocked_high == approx(5_085_000 * 0.20) # 1,017,000 + assert "joint lift" in m2.note + + # Move 3 — the trio lifts again, 4 → 5. + assert (m3.current_level, m3.target_level) == (4, 5) + assert m3.est_cost_low == approx(200_000 + 500_000 + 350_000) # 1,050,000 + assert m3.est_cost_high == approx(400_000 + 1_000_000 + 700_000) # 2,100,000 + assert m3.est_weeks == 20 + assert m3.value_unlocked_low == approx(2_542_500 * 0.15) + assert m3.value_unlocked_high == approx(5_085_000 * 0.15) # 762,750 + + # The ratio walk declines — the first unlock is the cheapest value. + ratios = [((m.value_unlocked_low + m.value_unlocked_high) / 2) + / ((m.est_cost_low + m.est_cost_high) / 2) + for m in (m1, m2, m3)] + assert ratios[0] > ratios[1] > ratios[2] + + +def test_structural_ties_hold_at_any_scores(config, baseline, scores): + vas = value_at_stake(config, baseline, scores) + assert vas.theoretical_annual_value_low <= vas.theoretical_annual_value_high + assert vas.realizable_18mo_low <= vas.realizable_18mo_high + assert vas.trapped_value_low <= vas.trapped_value_high + assert sum(d.theoretical_low for d in vas.driver_values) == approx( + vas.theoretical_annual_value_low) + assert sum(d.theoretical_high for d in vas.driver_values) == approx( + vas.theoretical_annual_value_high) + assert set(vas.binding_constraints) <= set(config.foundational_competencies) + assert len(vas.unlock_sequence) <= 3 + + +def test_weakest_and_binding_with_ties(config, baseline, scores): + assert weakest_foundational_score(config, scores) == 2 + # Drag process_discovery down to 2 as well — binding set becomes a pair. + tied = [s.model_copy(update={"score": 2}) + if s.competency_id == "process_discovery" else s for s in scores] + assert binding_constraints(config, tied) == ["process_discovery", "data_readiness"] + vas = value_at_stake(config, baseline, tied) + m1 = vas.unlock_sequence[0] + assert m1.competency_ids == ["process_discovery", "data_readiness"] + assert "joint lift" in m1.note + assert m1.est_cost_low == approx(120_000 + 300_000) + + +def test_unknown_inputs_raise_warnings(config, baseline, scores): + flagged = baseline.model_copy(update={"field_confidence": { + **baseline.field_confidence, "annual_contact_volume": "unknown"}}) + vas = value_at_stake(config, flagged, scores) + assert any("annual_contact_volume" in w and "unknown" in w for w in vas.warnings) + + +def test_stub_config_yields_empty_value(stub_config, baseline, scores): + vas = value_at_stake(stub_config, baseline, scores) + assert vas.theoretical_annual_value_low == 0 + assert vas.theoretical_annual_value_high == 0 + assert vas.unlock_sequence == [] + assert any("no value drivers" in w for w in vas.warnings) + + +def test_money_two_significant_figures(): + assert money(953_437.50) == "$950K" + assert money(2_542_500) == "$2.5M" + assert money(1_271_250) == "$1.3M" + assert money(5_085_000) == "$5.1M" + assert money(15_000_000) == "$15M" + assert money(202_500) == "$200K" + assert money(-450_000) == "-$450K" + assert money(85) == "$85" + assert money(0) == "$0" diff --git a/studies/202607_CX_Discovery_Workshop/README.md b/studies/202607_CX_Discovery_Workshop/README.md new file mode 100644 index 0000000..e1df16b --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/README.md @@ -0,0 +1,83 @@ +# 202607 — CX Exploration & Discovery Workshop + +A **live facilitation aid** for a CX discovery session, built on the +[Mercury Notebook Deliverable Pattern](../../docs/Mercury_Notebook_Pattern_V1-00.md). +Unlike the TEI business-case studies, this deliverable computes no dollars — +its "numbers" are **topic status and progress**. The Mercury stage is the +visual you share on a call or in a workshop while you work through the +questions; the question script and captured notes live backstage and export +as LLM input for the survey write-up or a downstream business case. + +## What the client sees (the stage) + +A calm **topic board**: each topic, its one-line scope, a status glyph, and — +for the topic under discussion — a **live sub-topic checklist**, above a +**progress bar** ("3/8 topics complete"). No wall of questions: you ask those. + +![board preview](docs/board_preview.png) + +You drive it from the sidebar — a **status** selector and a **notes** box per +topic, plus a **checkbox** per sub-topic. As the conversation moves you set a +topic *In progress*, tick sub-topics as you cover them, mark it *Complete* (or +*Skipped*), and jot answers. Every change re-renders the board and progress bar +(Mercury re-runs the cells below the widgets). + +## What you work from (backstage) + +JupyterLab and the exports carry the **facilitator question script** (all 95 +prompts, grouped by topic → sub-topic) and the **captured-session appendix** +(status + notes as a markdown table and one JSON block). Neither shows on the +Mercury stage. The 8 topics / 26 sub-topics / ~110-minute agenda are the +structured form of the source survey. + +## Layout + +``` +discoverylib/ # the engine — all content & logic + topics.py # the topic bank (verbatim anchor from the survey) + session.py # status vocabulary, progress, checklist, export payload + staging.py # stage/backstage detection (copied verbatim) +notebooks/cx_discovery.ipynb # the deliverable (generated — see below) +scripts/ + build_notebook.py # regenerates the notebook from cell sources + export_report.py # nbconvert → exports/*.html + *.md +tests/ # engine pins + stage/backstage test +docs/cx_discovery_survey.md # source survey (the original cxxm.md) +exports/ # generated report sources +``` + +## The notebook is generated + +The notebook wires ~42 Mercury widgets (a status selector + notes box per +topic, a checkbox per sub-topic), all derived from the topic bank so they can't +drift from `discoverylib`. Rather than hand-maintain that JSON, the notebook is +built from readable cell sources in +[`scripts/build_notebook.py`](scripts/build_notebook.py): + +```bash +python scripts/build_notebook.py # regenerate after editing a cell +``` + +Edit facilitation *content* (topics, sub-topics, prompts, scope, minutes) in +[`discoverylib/topics.py`](discoverylib/topics.py) — not in the notebook. + +## Run + +```bash +python -m venv .venv && source .venv/bin/activate +pip install -e ".[dev]" + +mercury --working-dir . # serve the stage (share this screen) +jupyter lab # analyst / facilitator view +pytest # engine pins + stage/backstage +jupyter nbconvert --to notebook --execute --inplace notebooks/cx_discovery.ipynb # gate +python scripts/export_report.py # exports/*.html + *.md for the LLM handoff +``` + +## Extending + +New or reshaped discovery content is a `discoverylib/topics.py` edit, a test +pin (`tests/test_topics.py` recounts, `tests/test_session.py` for new logic), +then `python scripts/build_notebook.py`. Add a topic and the sidebar controls, +board, checklist, script, gate, and export all pick it up — because they're all +generated from the bank. diff --git a/studies/202607_CX_Discovery_Workshop/config.toml b/studies/202607_CX_Discovery_Workshop/config.toml new file mode 100644 index 0000000..c7cae25 --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/config.toml @@ -0,0 +1,73 @@ +# Mercury app-shell theme — NTT DATA brand (light), modern surfaces. +# See docs/brand.md for the source palette. Loaded from the directory where +# you launch `mercury` (this study root); restart the server to apply. + +[main] +title = "CX Discovery Workshop" +favicon_emoji = "🧭" +footer = "CX Exploration & Discovery Workshop" +notebooks_button_label = "Workshops" + +[welcome] +header = "CX Discovery Workshop" +message = """ +The live visual for a CX exploration & discovery session. Topics and +progress render on screen for the client; the facilitator drives the +question script and captures notes backstage. Mark each topic's status in +the sidebar as the conversation moves — the board and the progress bar +update live. Afterward, export the captured notes for drafting with +`python scripts/export_report.py`. +""" + +[theme] +# ── Type — Georgia headings, Arial body (web-safe; no network fetch). ── +font_family = "Arial, 'Helvetica Neue', Helvetica, sans-serif" +heading_font_family = "Georgia, 'Times New Roman', Times, serif" +font_size = "15px" +font_weight = "normal" +heading_font_weight = "700" + +# ── Text — NTT ink scale ── +text_color = "#2e404d" +muted_text_color = "#586671" + +# ── Surfaces — white content on a soft neutral canvas ── +background_color = "#f4f5f6" +content_background_color = "#ffffff" +surface_color = "#ffffff" +card_background_color = "#f8f8f8" +border_color = "#d5d9db" +border_radius = "10px" + +# ── Accents — Future Blue ── +primary_color = "#0072bc" +accent_color = "#0072bc" +focus_border_color = "#0072bc" +hover_background_color = "#eef5fb" +selected_background_color = "#dcecfa" + +# ── Sidebar — clean white, hairline divider ── +sidebar_background_color = "#ffffff" +sidebar_text_color = "#2e404d" +sidebar_title_color = "#151d2c" +sidebar_shadow = "1px 0 0 #d5d9db" + +# ── Top bar — deep NTT navy ── +topbar_background_color = "#151d2c" +topbar_text_color = "#ffffff" +topbar_border_color = "rgba(255,255,255,0.08)" + +# ── Footer ── +footer_background_color = "#ffffff" +footer_text_color = "#586671" +footer_border_color = "#d5d9db" + +# ── Run button — subtle brand-blue gradient ── +run_button_background = "linear-gradient(180deg, #0087dc 0%, #0072bc 100%)" +run_button_background_hover = "linear-gradient(180deg, #1a93e6 0%, #0079c8 100%)" +run_button_text_color = "#ffffff" + +# ── Depth — soft, navy-tinted shadows ── +shadow_sm = "0 1px 2px rgba(21,29,44,0.05)" +shadow_md = "0 6px 18px rgba(21,29,44,0.08)" +shadow_lg = "0 16px 40px rgba(21,29,44,0.10)" diff --git a/studies/202607_CX_Discovery_Workshop/discoverylib/__init__.py b/studies/202607_CX_Discovery_Workshop/discoverylib/__init__.py new file mode 100644 index 0000000..40c3fe0 --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/discoverylib/__init__.py @@ -0,0 +1,62 @@ +""" +discoverylib — self-contained engine for the CX Exploration & Discovery +Workshop (Mercury Notebook Pattern). + +Not a financial model: this study's deliverable is a **live facilitation +aid**. The Mercury stage is the visual the client watches on the call — +topic board, the active topic's live sub-topic checklist, and a progress +headline ("3/8 topics complete"). The backstage (JupyterLab / nbconvert) +carries the facilitator's question script and the captured per-topic notes, +which the data-appendix export hands to an LLM to draft the survey write-up +or feed a downstream business-case study. + +Engine/presentation split (Pattern §2): the topic bank and all status / +progress logic live here; the notebook only arranges and renders them. +""" + +from .topics import ( + TOPIC_BY_KEY, + TOPIC_KEYS, + TOPICS, + SubTopic, + Topic, + topic, +) +from .session import ( + COMPLETE, + IN_PROGRESS, + NOT_STARTED, + SKIPPED, + STATUS_COLOR, + STATUS_GLYPH, + STATUS_LABEL, + STATUSES, + ChecklistItem, + Progress, + TopicState, + active_topic_key, + agenda_minutes, + build_session, + normalize_status, + progress, + session_json, + subtopic_checklist, + subtopic_id, +) +from .staging import backstage, on_stage + +__version__ = "0.1.0" + +__all__ = [ + # topic bank + "TOPICS", "TOPIC_BY_KEY", "TOPIC_KEYS", "Topic", "SubTopic", "topic", + # status vocabulary + "STATUSES", "STATUS_LABEL", "STATUS_GLYPH", "STATUS_COLOR", + "NOT_STARTED", "IN_PROGRESS", "COMPLETE", "SKIPPED", "normalize_status", + # progress + session + "Progress", "progress", "active_topic_key", "agenda_minutes", + "ChecklistItem", "subtopic_checklist", "subtopic_id", + "TopicState", "build_session", "session_json", + # staging + "on_stage", "backstage", +] diff --git a/studies/202607_CX_Discovery_Workshop/discoverylib/session.py b/studies/202607_CX_Discovery_Workshop/discoverylib/session.py new file mode 100644 index 0000000..941bbeb --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/discoverylib/session.py @@ -0,0 +1,251 @@ +""" +Session engine — the discovery workshop's "math". + +There are no dollars here; the quantities a facilitator and client watch are +**status** and **progress**. This module owns all of it so the notebook only +arranges outputs (Mercury Notebook Pattern §2, engine/presentation split): + +* the topic-status vocabulary (:data:`STATUSES`) and its display glyphs, +* :func:`progress` — the "3 / 8 topics complete" headline and its ratios, +* :func:`subtopic_checklist` — the live tick-list for the active topic, +* :func:`build_session` — assembles the full render/export state from the + raw widget inputs (per-topic status + free-text notes), +* :func:`session_json` — the machine-readable export payload (Pattern §5). + +Everything is a pure function of ``(status_by_topic, notes_by_topic, +done_subtopics)`` so the in-notebook gate can pin it and the export can dump +it. Unknown / missing keys degrade gracefully to "not started" so a +half-filled live session never crashes the render. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + +from .topics import TOPICS, TOPIC_BY_KEY, Topic + + +# ── Status vocabulary ──────────────────────────────────────────────── +# Order matters: it's the selector order and the legend order. "skipped" +# is terminal-but-not-complete (a topic consciously set aside), so it +# counts as resolved for the agenda but not toward completion. +NOT_STARTED = "not_started" +IN_PROGRESS = "in_progress" +COMPLETE = "complete" +SKIPPED = "skipped" + +STATUSES: tuple[str, ...] = (NOT_STARTED, IN_PROGRESS, COMPLETE, SKIPPED) + +STATUS_LABEL: dict[str, str] = { + NOT_STARTED: "Not started", + IN_PROGRESS: "In progress", + COMPLETE: "Complete", + SKIPPED: "Skipped", +} + +# Stage glyphs — calm, unambiguous at a glance on a shared screen. +STATUS_GLYPH: dict[str, str] = { + NOT_STARTED: "○", # open circle — pending + IN_PROGRESS: "◐", # half — under discussion + COMPLETE: "●", # filled — done + SKIPPED: "⊘", # slashed — set aside +} + +# Brand-aligned status colors (docs/brand.md). Muted gray pending, Future +# Blue active, Success Green complete, light gray skipped. +STATUS_COLOR: dict[str, str] = { + NOT_STARTED: "#a9b2b8", + IN_PROGRESS: "#0072bc", + COMPLETE: "#00a34c", + SKIPPED: "#c3c7ca", +} + + +def normalize_status(value: str | None) -> str: + """Coerce any widget value to a known status; default NOT_STARTED.""" + return value if value in STATUS_LABEL else NOT_STARTED + + +# ── Progress ───────────────────────────────────────────────────────── +@dataclass(frozen=True) +class Progress: + """The headline the client watches: completed vs. total topics, plus + the resolved (complete + skipped) count that drives the agenda burn.""" + + total: int + completed: int # status == complete + skipped: int + in_progress: int + not_started: int + + @property + def resolved(self) -> int: + """Topics no longer open for discussion (complete or skipped).""" + return self.completed + self.skipped + + @property + def fraction(self) -> float: + """Completed / total in [0, 1] — the progress-bar fill.""" + return self.completed / self.total if self.total else 0.0 + + @property + def label(self) -> str: + return f"{self.completed}/{self.total} topics complete" + + +def progress(status_by_topic: dict[str, str]) -> Progress: + """Tally topic statuses into the headline :class:`Progress`.""" + counts = {s: 0 for s in STATUSES} + for t in TOPICS: + counts[normalize_status(status_by_topic.get(t.key))] += 1 + return Progress( + total=len(TOPICS), + completed=counts[COMPLETE], + skipped=counts[SKIPPED], + in_progress=counts[IN_PROGRESS], + not_started=counts[NOT_STARTED], + ) + + +def active_topic_key(status_by_topic: dict[str, str]) -> str | None: + """The topic to spotlight on stage: the first in-progress topic, else + the first not-started one, else None (everything resolved).""" + for t in TOPICS: + if normalize_status(status_by_topic.get(t.key)) == IN_PROGRESS: + return t.key + for t in TOPICS: + if normalize_status(status_by_topic.get(t.key)) == NOT_STARTED: + return t.key + return None + + +# ── Sub-topic checklist (live, for the active topic) ───────────────── +@dataclass(frozen=True) +class ChecklistItem: + key: str + title: str + done: bool + + +def subtopic_checklist( + topic: Topic, done_subtopics: set[str] | frozenset[str] +) -> list[ChecklistItem]: + """The active topic's sub-topics as a tick-list. ``done_subtopics`` + holds the fully-qualified ``"."`` ids the + facilitator has ticked.""" + return [ + ChecklistItem(st.key, st.title, f"{topic.key}.{st.key}" in done_subtopics) + for st in topic.subtopics + ] + + +def subtopic_id(topic_key: str, subtopic_key: str) -> str: + """The fully-qualified id used in ``done_subtopics`` and the export.""" + return f"{topic_key}.{subtopic_key}" + + +# ── Agenda ─────────────────────────────────────────────────────────── +def agenda_minutes() -> int: + """Sum of the nominal per-topic minute budgets.""" + return sum(t.minutes for t in TOPICS) + + +# ── Full session state (render + export) ───────────────────────────── +@dataclass(frozen=True) +class TopicState: + key: str + title: str + scope: str + minutes: int + status: str + status_label: str + glyph: str + color: str + notes: str + subtopics_total: int + subtopics_done: int + + +def build_session( + status_by_topic: dict[str, str], + notes_by_topic: dict[str, str] | None = None, + done_subtopics: set[str] | frozenset[str] | None = None, +) -> dict[str, Any]: + """Assemble the complete session state the notebook renders and exports. + + Pure function of the three raw inputs; safe against missing keys. + """ + notes_by_topic = notes_by_topic or {} + done_subtopics = frozenset(done_subtopics or ()) + + topic_states: list[TopicState] = [] + for t in TOPICS: + status = normalize_status(status_by_topic.get(t.key)) + done = sum( + 1 for st in t.subtopics if subtopic_id(t.key, st.key) in done_subtopics + ) + topic_states.append( + TopicState( + key=t.key, + title=t.title, + scope=t.scope, + minutes=t.minutes, + status=status, + status_label=STATUS_LABEL[status], + glyph=STATUS_GLYPH[status], + color=STATUS_COLOR[status], + notes=(notes_by_topic.get(t.key) or "").strip(), + subtopics_total=len(t.subtopics), + subtopics_done=done, + ) + ) + + prog = progress(status_by_topic) + active = active_topic_key(status_by_topic) + return { + "topics": topic_states, + "progress": prog, + "active_topic_key": active, + "active_topic": TOPIC_BY_KEY[active] if active else None, + "agenda_minutes": agenda_minutes(), + } + + +def session_json( + session: dict[str, Any], meta: dict[str, Any] | None = None +) -> dict[str, Any]: + """The machine-readable export payload (Pattern §5): every captured + answer/status/note as plain JSON, ready to feed an LLM drafting the + survey write-up or business case. Plotly/HTML never carry this — the + appendix does.""" + prog: Progress = session["progress"] + return { + "study": "202607_CX_Discovery_Workshop", + "instrument": "CX Exploration & Discovery Workshop", + "meta": meta or {}, + "progress": { + "total_topics": prog.total, + "completed": prog.completed, + "skipped": prog.skipped, + "in_progress": prog.in_progress, + "not_started": prog.not_started, + "fraction_complete": round(prog.fraction, 4), + "label": prog.label, + }, + "agenda_minutes": session["agenda_minutes"], + "active_topic": session["active_topic_key"], + "topics": [ + { + "key": ts.key, + "title": ts.title, + "scope": ts.scope, + "status": ts.status, + "minutes": ts.minutes, + "subtopics_done": ts.subtopics_done, + "subtopics_total": ts.subtopics_total, + "notes": ts.notes, + } + for ts in session["topics"] + ], + } diff --git a/studies/202607_CX_Discovery_Workshop/discoverylib/staging.py b/studies/202607_CX_Discovery_Workshop/discoverylib/staging.py new file mode 100644 index 0000000..2ec7bec --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/discoverylib/staging.py @@ -0,0 +1,29 @@ +""" +Stage vs backstage — is this notebook render stakeholder-facing? + +The Mercury CLI (``mercury --working-dir …``) exports ``MERCURY_CONFIG_DIR`` +into the server process so the widget library can locate ``config.toml`` +(see ``mercury/config.py``); every kernel that server spawns inherits it. +JupyterLab and nbconvert kernels don't have it. That makes the variable a +reliable signal for "the audience is looking" (the stage) versus an +analyst session or a headless export run (backstage). + +Diagnostics routed through :func:`backstage` stay visible in JupyterLab +and land in the nbconvert exports (where the machine-readable appendix +must appear for LLM consumption) but never render in the Mercury app. +""" + +from __future__ import annotations + +import os + + +def on_stage() -> bool: + """True when running under the Mercury app (stakeholder-facing).""" + return os.getenv("MERCURY_CONFIG_DIR") is not None + + +def backstage(*args, **kwargs) -> None: + """``print`` that renders only backstage (JupyterLab, nbconvert).""" + if not on_stage(): + print(*args, **kwargs) diff --git a/studies/202607_CX_Discovery_Workshop/discoverylib/topics.py b/studies/202607_CX_Discovery_Workshop/discoverylib/topics.py new file mode 100644 index 0000000..b1a4091 --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/discoverylib/topics.py @@ -0,0 +1,428 @@ +""" +The discovery topic bank — verbatim source record for the CX Exploration & +Discovery workshop. + +This is the study's ``*_VERBATIM`` anchor (Mercury Notebook Pattern): the +facilitation content, structured but **never paraphrased away from** the +source survey ``docs/cx_discovery_survey.md`` (the original ``cxxm.md``). +Editing the wording of a prompt here is editing the anchor — do it against +the survey, not the notebook. + +Shape +----- +``TOPICS`` is an ordered tuple of :class:`Topic`. Each topic owns an ordered +tuple of :class:`SubTopic`; each sub-topic owns the ordered facilitator +prompts (the questions you actually ask). The stage shows topic titles, the +one-line ``scope`` per topic, and — for the active topic — the sub-topic +titles as a live checklist. The prompts stay **backstage** (your script); +they never render on the client's screen. + +Every topic carries: + +* ``key`` — stable slug (snake_case); the identity used by widgets, notes, + status, and the JSON export. NEVER renumber or rename casually — + captured notes key off it. +* ``title`` — client-facing heading shown on stage. +* ``scope`` — one neutral line shown under the title on stage, so the client + stays oriented without being led by the questions. +* ``minutes`` — nominal facilitation budget, summed into the agenda estimate. + +The content is deliberately data, not prose in the notebook: it is testable, +diffable, and exportable, and the notebook only arranges it. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field + + +@dataclass(frozen=True) +class SubTopic: + """A discussion thread within a topic; its title shows on stage when the + topic is active, its prompts are the backstage facilitation script.""" + + key: str + title: str + prompts: tuple[str, ...] = () + + +@dataclass(frozen=True) +class Topic: + """A client-facing discovery topic: the unit the progress bar counts.""" + + key: str + title: str + scope: str + minutes: int + subtopics: tuple[SubTopic, ...] = field(default_factory=tuple) + + @property + def prompt_count(self) -> int: + return sum(len(st.prompts) for st in self.subtopics) + + +# ── The topic bank ─────────────────────────────────────────────────── +# Ordered as a workshop runs: context first, then the operational areas, +# then the enabling functions, closing on reporting & insight. Wording of +# prompts tracks docs/cx_discovery_survey.md (cxxm.md). + +TOPICS: tuple[Topic, ...] = ( + Topic( + key="background", + title="Background & Organization", + scope="Lines of business, channels, org structure, decision-making", + minutes=15, + subtopics=( + SubTopic( + "lines_of_business", "Lines of business & scope", + ( + "How many distinct lines of business are supported in the " + "contact centre? (e.g. commercial, residential, retail, " + "wholesale)", + "Are you using the contact centre for internal uses such as " + "help desk, finance, HR?", + "Payment card / PCI in scope?", + "What are the availability SLAs or targets for your " + "technology platform?", + ), + ), + SubTopic( + "channels_supported", "Channels supported", + ( + "Which channels do you support today? (Apps, Voice, Video, " + "Chat, SMS, Email, Social Media, Digital Assistants)", + ), + ), + SubTopic( + "org_structure", "Org & reporting structure", + ( + "Mini org chart — reporting structure up to the executive " + "leader.", + "Are your contact centres managed by the same person? " + "(Managers / Team Leads / Agents)", + "Who carries the cost of contact centre agents and " + "supervisors?", + "What revenue is generated by the contact centre?", + ), + ), + SubTopic( + "decision_making", "Decision-making & priorities", + ( + "Is decision-making centralized or decentralized?", + "Who are the key decision makers for changes to the contact " + "centre?", + "How important is CX & EX to your organization's strategy? " + "Is there an executive accountable for CX (CXO, CDO)?", + "Of your leading offers, what is the customer's top priority?", + "Competitive pressures?", + "Any pending or recent acquisitions or spinoffs affecting IT " + "infrastructure and services?", + ), + ), + SubTopic( + "problems_today", "Problems & causes today", + ( + "What do you view as the problems in your contact centre " + "today, and the primary causes?", + "Any in-flight projects — CX or EX improvement initiatives?", + "Are your customer experiences personalized?", + ), + ), + ), + ), + Topic( + key="cx_strategy", + title="CX Strategy", + scope="How CX value is defined, measured, and organized to deliver", + minutes=15, + subtopics=( + SubTopic( + "value_definition", "Value & strategic position", + ( + "How is the value of Customer Experience defined within your " + "organization? Is CX a key BPI, recognized & measured as a " + "financial value?", + "What are the key capabilities / services delivered by the " + "contact centre?", + "How are you using CX innovation to create market " + "disruption?", + "How are competitors using CX to create competitive " + "differentiation?", + ), + ), + SubTopic( + "operating_model", "Organization & operating model", + ( + "Is there a CX team? Do the CX insights team regularly " + "educate the business?", + "Who are the key decision makers for investment and changes " + "to the contact centre? Channel management strategy?", + "What are the teams, and how are processes managed?", + "Describe your automation strategy. Who is your leader for " + "Data & AI?", + ), + ), + SubTopic( + "insight_and_voc", "Insight & Voice of Customer", + ( + "How do you use analytics & data to generate a consolidated " + "view of your customer experience?", + "Is there a VOC program in place? ROI / business value " + "known?", + "How do customers rate the experience they receive (0–5)?", + ), + ), + SubTopic( + "continuous_improvement", "Continuous improvement", + ( + "How is customer insight used to drive CX improvement, " + "loyalty and profitability? How do you anticipate needs?", + "Do you have a clear set of CX design guidelines? (Personas, " + "Journey Mapping, Tools)", + "KPI targets for CX — CSAT, NPS, CES? How are you doing?", + ), + ), + SubTopic( + "employee_engagement", "Employee engagement", + ( + "Describe your employee / agent engagement strategy.", + "How engaged are your people in delivering the customer " + "experience?", + "Do you have a VoA / VoE program in place? How are you " + "doing?", + ), + ), + ), + ), + Topic( + key="channels", + title="Channels", + scope="Inbound & outbound volumes, metrics, contact reasons", + minutes=20, + subtopics=( + SubTopic( + "inbound_context", "Inbound context", + ( + "Hours of operation — any 24×7?", + "Who contacts the contact centre? (Demographics, their " + "situation)", + "Are certain callers or groups prioritized?", + "Languages? (English, Canadian French, Spanish, other)", + ), + ), + SubTopic( + "voice_metrics", "Voice & video metrics", + ( + "Average number of active agents (voice / video).", + "Toll-free numbers & DIDs — approximate quantities.", + "Average Wait Time, Abandon rate, Handle Time, Hold Time, " + "After-call work time.", + "Time to authenticate a caller.", + "% of calls transferred — internally / externally (3rd " + "parties)?", + "Courtesy callback / virtual hold? Post-call survey? First " + "Call Resolution rate? Average revenue per call (sales)?", + ), + ), + SubTopic( + "digital_channels", "Digital channels", + ( + "Email — range of logged-in users, response time, email " + "server.", + "Chat — web (internal/external), app-embedded, SMS, " + "Messenger, WhatsApp, Telegram, iMessage.", + "Website forms, mobile apps.", + ), + ), + SubTopic( + "inbound_reasons", "Inbound contact reasons", + ( + "Top 3–5 inbound contact reasons and approximate % of calls.", + "Cost per call? Average Handle Time?", + "Busiest / least busy days? Seasonal variances?", + "Most difficult, commonly occurring calls? Easiest commonly " + "occurring call?", + ), + ), + SubTopic( + "outbound", "Outbound", + ( + "Hours of operation.", + "Voice (preview / predictive dialer volume), email, SMS, " + "recorded announcement ports.", + "Self-service applications, live agent connect, campaign " + "management, DNC management.", + "Top 3–5 outbound contact reasons and approximate % of " + "calls.", + "After-call work?", + ), + ), + ), + ), + Topic( + key="agent_environment", + title="Agent & Supervisor Environment", + scope="Locations, endpoints, desktop, applications, knowledge", + minutes=10, + subtopics=( + SubTopic( + "locations_endpoints", "Locations & endpoints", + ( + "Location types — WFH / offices.", + "Hard phone, soft phone, CODEC, wireless headset?", + "Agent greeting / pre-recorded messages, whisper " + "announcement.", + "PC — desktop, laptop, VDI.", + ), + ), + SubTopic( + "desktop_apps", "Desktop & applications", + ( + "Agent & supervisor desktop — omnichannel? Custom gadgets, " + "screen pops, workflows.", + "Standard browser? SSO?", + "Applications used to handle calls.", + "Knowledge Management.", + ), + ), + ), + ), + Topic( + key="routing_automation", + title="Routing & Automation", + scope="Self-service, IVR, speech, virtual agents, agent assist, RPA", + minutes=15, + subtopics=( + SubTopic( + "self_service", "Self-service & IVR", + ( + "IVR persona — branding, style guides, voice actors?", + "DTMF and/or speech? Speech recognition, TTS, NLU, voice " + "biometrics.", + "Self-service applications — ID & validate, deflection, " + "situational offer (outage / time of day / scheduled).", + "API integration (CRM). Intent capture, intent prediction, " + "offer push on prediction / account attribute.", + ), + ), + SubTopic( + "virtual_agents", "Virtual agents & assist", + ( + "Virtual agents — which processes?", + "Agent assist?", + "RPA?", + "Current challenges or desired capabilities. Desire to " + "automate. DevOps team?", + ), + ), + SubTopic( + "digital_assistants", "Digital assistant apps", + ( + "Alexa, Google Assistant, Siri?", + ), + ), + ), + ), + Topic( + key="workforce_engagement", + title="Workforce Engagement", + scope="Call recording / QM, WFM, agent self-service, integrations", + minutes=20, + subtopics=( + SubTopic( + "recording_qm", "Call recording & Quality Management", + ( + "How is call recording used? Compliance, screen capture, " + "voice transcription (real-time?), desktop analytics, " + "retention period.", + "Quality team — who do they report to, how many people? " + "Scorecards, score method & metrics, number of assessments, " + "coaching, live monitor.", + "Locations with call recording. Number of named agents.", + ), + ), + SubTopic( + "workforce_management", "Workforce management", + ( + "Recruitment process, required qualifications, average " + "tenure, attrition rate, internal moves.", + "Do you measure agent & supervisor experience? Recognition " + "program?", + "Adherence measure — KPIs, gamification, shift length, " + "breaks, annualized utilization %.", + "Forecasting & scheduling — peak volume, historical data, " + "algorithms, WFM interval (15/30 min).", + "Intraday / real-time adherence — what happens when out of " + "compliance?", + "Payroll integration (ADP / Workday). Satisfaction with " + "current tool(s)? Multiskilled agents, FTE calculations.", + ), + ), + SubTopic( + "agent_self_service", "Agent self-service & integrations", + ( + "Agent self-service — absences, shift bids / swaps, " + "performance metrics.", + "Number of named agents.", + "Integration to 3rd party — outsourcer / overflow, payroll.", + ), + ), + ), + ), + Topic( + key="training", + title="Training", + scope="Onboarding, format, assessment, eLearning, QM integration", + minutes=5, + subtopics=( + SubTopic( + "onboarding", "Onboarding & enablement", + ( + "Onboarding process — how long, training format, " + "assessment?", + "eLearning?", + "QM integration?", + ), + ), + ), + ), + Topic( + key="reporting_insights", + title="Reporting & Insights", + scope="Real-time & historical reporting, analytics, BI, CRM", + minutes=10, + subtopics=( + SubTopic( + "reporting", "Reporting", + ( + "Real-time and historical — what are the key metrics you " + "report on?", + "Data source integration, dashboards, wallboards, agent & " + "supervisor status.", + ), + ), + SubTopic( + "analytics_insights", "Analytics & insights", + ( + "Integrated view of customer details and contact history? " + "CRM?", + "Does the contact centre collect and use customer insight? " + "Predictive engagement?", + "What data analysis do you perform? Analytics / BI team — how " + "many people? BI platform?", + "Executive-level reporting? Marketing team interlock?", + ), + ), + ), + ), +) + + +# ── Lookups ────────────────────────────────────────────────────────── +TOPIC_BY_KEY: dict[str, Topic] = {t.key: t for t in TOPICS} +TOPIC_KEYS: tuple[str, ...] = tuple(t.key for t in TOPICS) + + +def topic(key: str) -> Topic: + """Return the topic with ``key`` (raises ``KeyError`` if unknown).""" + return TOPIC_BY_KEY[key] diff --git a/studies/202607_CX_Discovery_Workshop/docs/board_preview.png b/studies/202607_CX_Discovery_Workshop/docs/board_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..18dced97116a4b6b09d03ba4089d695dfc939f9b GIT binary patch literal 100121 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 Rl(**xabanpf_FOJ{|h{KTdV*8 literal 0 HcmV?d00001 diff --git a/studies/202607_CX_Discovery_Workshop/docs/cx_discovery_survey.md b/studies/202607_CX_Discovery_Workshop/docs/cx_discovery_survey.md new file mode 100644 index 0000000..0c15e2c --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/docs/cx_discovery_survey.md @@ -0,0 +1,453 @@ +Contact Center Exploration & Discovery Workshops +The Contact Center Discovery and Exploration workshops allow us to gain a clear perspective of your contact center operations. The discovery workshop is focused on developing an understanding of the current state architecture and IT support. + +I’ve attached a contact center survey to collect information and context in advance of the workshop and is also useful to develop business cases. + +# CX Exploration + +## Background +How many distinct lines of business are supported in the contact centre? + (eg, commercial, residential, retail, wholesale, etc) +Are you using contact center for internal Uses such as help desk, finance, HR, etc.? + +What channels do you support? + Apps + Voice + Video + Chat + SMS + Email + Social Media + Digital Assistants + +Payment card/PCI? + +What are the availability SLAs or targets for your technology platform? + +Mini org chart + +Reporting structure + - Executive leader + +What is the structure of decision making in their organization? Centralized or decentralized? + - Who are the key decision makers for implementing a plan for changes to the contact centre? + +How important is CX & EX to your organization's strategy? + - Is there an executive that is accountable for CX? CXO, CDO? + +Of your leading offers, what is the customer's top priority? + +Competitive pressures? + +Are their pending or recent acquisitions or spinoffs that require changes to their IT infrastructure and services? + +What do they view as the problems in their contact centre today and what are the primary causes? + +CX / Customer Success Leadership: +Are your contact centers managed by the same person? + - Managers: + - Team Leads: + - Agents: + +Who carries the cost of contact centre agents and supervisors? + +What revenue is generated by the contact center? + +Do you have KPI targets for CX?: + CSAT: + NPS: + CES: + How are you doing? + +Is there a VOC program in place? + • ROI/business value known? + • How do customers rate the experience they receive from your organization? 0-5 + + +What are the key features of their corporate culture? + +Is their a Voice of the Agent, or Employee satisfaction survey in place? + - How are they doing? + + +Automation strategy? + +Any inflight projects? + - Any CX or EX improvement initiatives? + +Decision + +Channel management strategy? + +Are your customer experiences personalized? + +Do you have a clear set of design guidelines for CX? + Personas + Journey Mapping + Tools: + +How are processes managed? + +## CX Strategy +How is the value of Customer Experience defined within your organization? + - CX is a key BPI, recognized & measured as a financial value + + + +Strategic Value +What revenue is generated by the contact center? + +What are the key capabilities / services that are delivered by the contact centre? + + + +Proposition +How are you using CX innovation to create market disruption? + +How are competitors using CX to create competitive differentiation? + + +Organization Structure & Operating Model +Is there an executive that is accountable for CX? CXO, CDO? + +Is there a CX team? + Do the CX insights team regularly educate the business + +How are decisions made in the organization, is it centralized or decentralized? + - Who are the key decision makers for investment and changes to the contact centre'? + - Channel management strategy? + + +Who carries the cost of contact centre agents and supervisors? + +Are they managed by the same person? + + +What are the teams? + +How are processes managed? + +Describe your automation strategy. Are there any desires or goals related to the contact centre? + - Who is your leader for Data & AI? + + + +Are there any inflight projects that would impact the contact centre? + +Are there recent or pending acquisitions or spinoffs? + +Insight +How do you use analytics & data to generate a consolidated view of your customer experience? + + +Is there a VOC program in place? + • ROI/business value known? + • How do customers rate the experience they receive from your organization? 0-5 + + +Approach +Continuous Improvement +How is customer insight used to drive CX improvement, loyalty and profitability? +How do you anticipate needs? + +Do you have a clear set of CX design guidelines for CX? + Personas + Journey Mapping + Tools: + +Do you have KPI targets for CX?: + CSAT: + NPS: + CES: + How are you doing? + + +Employee Engagement +Please describe you about your employee / Agent engagement strategy + +How engaged are your people in delivering the customer experience? + +Do you have a VoA/VoE program in place? How are you doing? + +## Channels + +May 6, 2025 +2:52 PM + +Inbound + +Hours of operation + +Who contacts the contact center? (Demographics, their situation) + +Are certain callers or groups prioritized? + +Languages? + English + Canadian French + Spanish + + Video + Average number of active agents: + Voice + Average number of active agents: + Toll Free numbers & DIDs: + Approximate quantities or a list + Hours of operation? Any 24x7? + Average Wait Time: + Average Abandon rate: + Average Handle Time: + Average Call Hold Time: + Average After work call time: + Time to authenticate a caller: + % of calls transferred? + Internally? + Externally? + 3rd parties handling certain types of calls, or being conferenced in? + Courtesy Callback/Virtual Hold + Post Call Survey + First Call Resolution Rate? + Average revenue per call (sales)? + Email, range of logged in users: + ○ Response time: + ○ Email server + Chat, range of logged in users: + Web Chat Internal + Web Chat External + App Integration / embedded + SMS + Facebook Messenger + WhatsApp + Telegram + iMessage + Web Site Forms + Mobile Apps + +Top 3-5 Inbound contact reasons and approximate % of calls: + 1. + +Cost Per call? +Average Handle Time? + +Busiest days: + +Least busy days: + +Seasonal variances? + +What are your most difficult, commonly occurring calls? + +What is the easiest commonly occurring call? + + +Outbound + +Hours of operation + + Voice, range of logged in users: + Preview, volume + Predictive dialer + Email, range of logged in users: + SMS, range of logged in users: + Recorded announcement, ports: + Self service applications + Transfer to agent + Live agent connect + Campaign management + DNC management + +Top 3-5 outbound contact reasons and approximate % of calls: + 1. + + +After call work? + + +## Agent & Supervisor Environment +Location types: + - WFH: + - Offices: + + Hard phone + Soft phone + CODEC? + Headset, wireless?: + Agent greeting or pre-recorded messages + Whisper announcement +PC + Desktop + Laptop + VDI +Agent & Supervisor desktop (omnichannel?): + Custom gadgets + Screen pops + Workflows +Standard browser: +SSO: +Applications used to handle calls: +Knowledge Management: + +## Routing & Automation + Self Service + IVR Persona? + Branding? + Style guides? + Voice actors? + DTMF + Speech + Speech recognition + Text To Speech + Natural Language Understanding + Voice Biometrics + Self service applications: + ID & Validate + Deflection + Situational Offer (Outage/ Time of Day / Scheduled) + API integration: + CRM + Intent Capture + Intent prediction + Offer push based on prediction/account attribute + Virtual Agents + Processes + Agent Assist + RPA + Current challenges or desired capabilities + Process management + Desire to automate + DevOps team? + +Digital Assistant Apps + Alexa + Google Assistant + Siri + + +## Routing & Automation + Self Service + IVR Persona? + Branding? + Style guides? + Voice actors? + DTMF + Speech + Speech recognition + Text To Speech + Natural Language Understanding + Voice Biometrics + Self service applications: + ID & Validate + Deflection + Situational Offer (Outage/ Time of Day / Scheduled) + API integration: + CRM + Intent Capture + Intent prediction + Offer push based on prediction/account attribute + Agent Assist + RPA + Current challenges or desired capabilities + Process management + Desire to automate + DevOps team? + +Digital Assistant Apps + Alexa + Google Assistant + Siri + + +Workforce Engagement + +May 6, 2025 +2:50 PM + +Call Recording/QM + • How is call recording used? + Compliance + Screen capture + Voice transcription + Real time + Desktop analytics + Retention period + Quality Management + Do you have a quality team? + Who do they report to? + How many people work for the team? + Scorecards + Score method and metrics? + How many assessments are conducted? + Coaching + Live Monitor + • Locations with CR + • Number of Named Agents: + + +Workforce Engagement + • What is your recruitment process? + • What qualifications are required for the call center? + • What is the average staff tenure? + • What is the attrition rate? + • What proportion of the staff leave for other positions in the company per annum? + ○ Are staff hired for the CC from other parts of the organization? + • Do you measure agent & supervisor experience? + ○ How are they doing? + ○ What type of recognition program do you have in place? + • Agent adherence measure? + ○ KPIs + ○ Gamification + ○ How long is a shift? + ○ What breaks are allocated + ○ What annualized utilization % do you calculate? + • Forecasting & Scheduling + ○ Peak call volume days, time of month, year? + ○ Validate historical data + ○ How are calculations performed (algorithms used) + ○ WFM Interval (15/30 minutes) + • Intraday/ Realtime adherence + ○ What happens when you are out of compliance, surprises happen? + • Payroll Integration + ○ Payroll platform + • Satisfaction with current tool(s)? + ○ Multiskilled agents + ○ FTE Calculations + • Agent self-service? + ○ How are absences reported? + ○ Shift bids / swaps + ○ Performance metrics + • Number of Named Agents: + • Integration to 3rd party + ○ outsourcer / overflow: + ○ Payroll: ADP / Workday + + +Training + • Onboarding process + ○ How long is it? + ○ Training format? + ○ Assessment? + eLearning + QM Integration + +## Reporting & Insights +Reporting + • Real time + • Historical + • What are the key metrics that you report on? + Data source integration + Dashboards + Wallboards + Agent & Supervisor status + +Analytics & Insights + Do you have an integrated view of customer details and contact history? + CRM: + Does your contact centre collect and use customer insight? + Predictive engagement: + What sort of data analysis do you perform? + Do you have an analytics or business insights team? + How many people? + BI Platform: + What executive level reporting do you perform? + Marketing Team interlock + diff --git a/studies/202607_CX_Discovery_Workshop/exports/.gitkeep b/studies/202607_CX_Discovery_Workshop/exports/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/studies/202607_CX_Discovery_Workshop/notebooks/cx_discovery.ipynb b/studies/202607_CX_Discovery_Workshop/notebooks/cx_discovery.ipynb new file mode 100644 index 0000000..b625843 --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/notebooks/cx_discovery.ipynb @@ -0,0 +1,5353 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9cbdb2fa", + "metadata": {}, + "source": [ + "# CX Exploration & Discovery Workshop\n", + "\n", + "The live visual for a discovery session. On screen the client sees the\n", + "**topic board** — each topic, its one-line scope, and a status glyph — the\n", + "**live sub-topic checklist** for whatever we're discussing now, and a\n", + "**progress headline** (\"3/8 topics complete\"). You drive the conversation\n", + "from the question script (which stays backstage); the client is never shown\n", + "a wall of questions.\n", + "\n", + "**This notebook is the deliverable.** Serve it with\n", + "`mercury --working-dir .` and share that screen; mark each topic's status in\n", + "the sidebar as the discussion moves and tick sub-topics as you cover them —\n", + "the board and progress bar update live. Capture answers in the per-topic\n", + "notes boxes. Afterward, `python scripts/export_report.py` writes an\n", + "LLM-readable report source (notes + status + progress as markdown and JSON)\n", + "to feed the survey write-up or a downstream business-case study.\n", + "\n", + "All content and logic live in `discoverylib/` — the notebook only arranges\n", + "and renders them.\n", + "\n", + "Confidence legend: 🟢 confirmed · 🟡 estimated · 🔴 unknown — used in the\n", + "captured notes, not on the client-facing board." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "499aa272", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:20:56.680703Z", + "iopub.status.busy": "2026-07-19T23:20:56.680435Z", + "iopub.status.idle": "2026-07-19T23:20:56.829264Z", + "shell.execute_reply": "2026-07-19T23:20:56.826221Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "discoverylib loaded — 8 topics · 26 sub-topics · 95 prompts\n" + ] + } + ], + "source": [ + "# ── Setup ──────────────────────────────────────────────────────────\n", + "import sys, pathlib\n", + "_ROOT = pathlib.Path.cwd()\n", + "if not (_ROOT / \"discoverylib\").exists(): # notebook lives in notebooks/\n", + " _ROOT = _ROOT.parent\n", + "sys.path.insert(0, str(_ROOT))\n", + "\n", + "import html as _html\n", + "\n", + "import mercury as mr\n", + "\n", + "# Single source of truth — the topic bank and all status/progress logic\n", + "# live in the library; only presentation (and Mercury widgets) lives here.\n", + "from discoverylib import (\n", + " TOPICS, STATUSES, STATUS_LABEL, STATUS_GLYPH, STATUS_COLOR,\n", + " build_session, subtopic_checklist, subtopic_id, session_json,\n", + ")\n", + "from discoverylib.staging import backstage\n", + "\n", + "# ── Brand palette (docs/brand.md, light theme) ─────────────────────\n", + "NAVY, INK, MUTED = \"#151d2c\", \"#2e404d\", \"#586671\"\n", + "BLUE, GREEN, LINE = \"#0072bc\", \"#00a34c\", \"#e2e6e9\"\n", + "CARD_BG, HAIRLINE = \"#f8f8f8\", \"#d5d9db\"\n", + "FONT = \"Georgia, 'Times New Roman', serif\"\n", + "BODY_FONT = \"Arial, 'Helvetica Neue', Helvetica, sans-serif\"\n", + "\n", + "\n", + "def esc(s):\n", + " return _html.escape(str(s))\n", + "\n", + "\n", + "backstage(f\"discoverylib loaded — {len(TOPICS)} topics · \"\n", + " f\"{sum(len(t.subtopics) for t in TOPICS)} sub-topics · \"\n", + " f\"{sum(t.prompt_count for t in TOPICS)} prompts\")" + ] + }, + { + "cell_type": "markdown", + "id": "6f0ea0f6", + "metadata": {}, + "source": [ + "## How to run this session\n", + "\n", + "- **Sidebar** — one **status** selector and a **notes** box per topic, plus a\n", + " **sub-topic checkbox** for each thread. As the conversation moves, set the\n", + " topic you're on to *In progress*, tick sub-topics as you cover them, mark\n", + " the topic *Complete* (or *Skipped*) when you move on, and jot answers in its\n", + " notes box.\n", + "- **Stage** (this page) — the client-facing board and progress bar below\n", + " re-render on every change.\n", + "- **Backstage** (JupyterLab / the export) — the facilitator question script and\n", + " the captured-notes appendix. Neither shows on the Mercury stage." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4ea73b8c", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:20:56.833025Z", + "iopub.status.busy": "2026-07-19T23:20:56.832404Z", + "iopub.status.idle": "2026-07-19T23:20:57.008204Z", + "shell.execute_reply": "2026-07-19T23:20:57.006631Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "10c8be84f1804c86a5b938888f72c62a", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "10c8be84f1804c86a5b938888f72c62a", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "e74f98220a094696b7e2525782c140d0", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "e74f98220a094696b7e2525782c140d0", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "5072fb8217314fbe9137e9d55ad9358d", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "5072fb8217314fbe9137e9d55ad9358d", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "00b9b1239d634bc69d67508148b4d5df", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "00b9b1239d634bc69d67508148b4d5df", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "7d9b61e8dfaf472fabd6a2ce047d6729", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "7d9b61e8dfaf472fabd6a2ce047d6729", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "60ee47d42b1d4066877dec2b86577a01", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "60ee47d42b1d4066877dec2b86577a01", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "47a1106486e6494e90dfd0616fc7fc0f", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "47a1106486e6494e90dfd0616fc7fc0f", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "9adb705fc7cc420da7965276388fafe8", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "9adb705fc7cc420da7965276388fafe8", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "b715b892818b46019201b5a688f70dcf", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "b715b892818b46019201b5a688f70dcf", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "20ce1fa7b06e4f86bb137706851bcf84", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "20ce1fa7b06e4f86bb137706851bcf84", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "177b5301a0234fdf93277284006e5601", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "177b5301a0234fdf93277284006e5601", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "fe8ea7220e28420aa3f4b8901b51a2d9", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "fe8ea7220e28420aa3f4b8901b51a2d9", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "56b21c34e0234fc0b0d83fe950fca3a4", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "56b21c34e0234fc0b0d83fe950fca3a4", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "1d38c9ccfa4444deb04cf2fb46f91ec0", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "1d38c9ccfa4444deb04cf2fb46f91ec0", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "58daff561a724695ba1d32ba3771bd1e", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "58daff561a724695ba1d32ba3771bd1e", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "add2dcc4edde499581741451b25b7559", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "add2dcc4edde499581741451b25b7559", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "d9f9a188dd4f48f7a30fcb41e78e8257", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "d9f9a188dd4f48f7a30fcb41e78e8257", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "7792e81022c344b89b11a308207a6bbe", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "7792e81022c344b89b11a308207a6bbe", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "430f1b8e205b4de7a3c54e8f3db18107", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "430f1b8e205b4de7a3c54e8f3db18107", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "9deaa72bbf0948988dfdb57bcf670f40", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "9deaa72bbf0948988dfdb57bcf670f40", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "f1920f6a825349f1be5e9cd1a22b0708", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "f1920f6a825349f1be5e9cd1a22b0708", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "3f9c462ee81646caaac03ebeb9055ae1", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "3f9c462ee81646caaac03ebeb9055ae1", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "15e5250a35484ff0a4b5e5373d0527a0", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "15e5250a35484ff0a4b5e5373d0527a0", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "6fa3e0db0dd3463993acc9c18ac10805", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "6fa3e0db0dd3463993acc9c18ac10805", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "59e3152d6bde44f4bf75a8d88441b3ec", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "59e3152d6bde44f4bf75a8d88441b3ec", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "302c515cbf2f445a8e96a3e557dacfda", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "302c515cbf2f445a8e96a3e557dacfda", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "2f744f3e85324a6c9c56a9c68c37d8af", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "2f744f3e85324a6c9c56a9c68c37d8af", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "15d0aa6ac0714e3685af841c84d13a48", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "15d0aa6ac0714e3685af841c84d13a48", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "0a51d9b2d7ad4cd386911034dd9aecc5", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "0a51d9b2d7ad4cd386911034dd9aecc5", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "8755ad066ef049a4beb4ca76d1fc08c6", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "8755ad066ef049a4beb4ca76d1fc08c6", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "4e139491242c4e93a13081aca8905d20", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "4e139491242c4e93a13081aca8905d20", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "902b8644258e4e0394ab71de2de93fe6", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "902b8644258e4e0394ab71de2de93fe6", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "cb06370551d3496ca2e374ed62bf6620", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "cb06370551d3496ca2e374ed62bf6620", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "34862dfebebd43c7a5705d7e63a166d6", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "34862dfebebd43c7a5705d7e63a166d6", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "28bce7ca5a814f07a6276251f0521d8a", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "28bce7ca5a814f07a6276251f0521d8a", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "d1318d0516724e41b98ac4bc97d5501f", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "d1318d0516724e41b98ac4bc97d5501f", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "0e24ed58f9b9415a90fe052a4e3342bf", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "0e24ed58f9b9415a90fe052a4e3342bf", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "6580589f5f7b412f89671530df13090d", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "6580589f5f7b412f89671530df13090d", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "9831e05d2a98408b9b4072ff81aef0cd", + "position": "sidebar", + "widget": "SelectWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "9831e05d2a98408b9b4072ff81aef0cd", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "b784c44f81fd4663b94098ffe046af71", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "b784c44f81fd4663b94098ffe046af71", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "4a36f1141ebc4915af04a7112b8210d3", + "position": "sidebar", + "widget": "CheckboxWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "4a36f1141ebc4915af04a7112b8210d3", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/mercury+json": { + "model_id": "4b2fd66370df42679080cb60015fbe3c", + "position": "sidebar", + "widget": "TextInputWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "4b2fd66370df42679080cb60015fbe3c", + "version_major": 2, + "version_minor": 1 + }, + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ── Session controls (Mercury sidebar — widgets ONLY, no other output) ─\n", + "# Generated from the topic bank: per topic a status selector + notes box,\n", + "# per sub-topic a checkbox. Mercury re-runs only cells BELOW this one, so\n", + "# every .value is read in the next cell down — never here.\n", + "#\n", + "# _status_w[topic_key] -> Select (Not started / In progress / …)\n", + "# _notes_w[topic_key] -> TextInput (captured answers, backstage)\n", + "# _sub_w[(topic_key, sub)] -> CheckBox (covered?)\n", + "# Labels are distinct per widget, so Mercury's label-keyed widget cache\n", + "# never collides across topics/sub-topics.\n", + "_status_w, _notes_w, _sub_w = {}, {}, {}\n", + "\n", + "for _t in TOPICS:\n", + " _status_w[_t.key] = mr.Select(\n", + " label=f\"{_t.title} — status\",\n", + " value=STATUS_LABEL[STATUSES[0]],\n", + " choices=[STATUS_LABEL[s] for s in STATUSES],\n", + " )\n", + " for _st in _t.subtopics:\n", + " _sub_w[(_t.key, _st.key)] = mr.CheckBox(\n", + " value=False, appearance=\"box\",\n", + " label=f\"{_t.title}: {_st.title}\")\n", + " _notes_w[_t.key] = mr.TextInput(\n", + " label=f\"{_t.title} — notes\", value=\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "aae1a098", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:20:57.011339Z", + "iopub.status.busy": "2026-07-19T23:20:57.011038Z", + "iopub.status.idle": "2026-07-19T23:20:57.020306Z", + "shell.execute_reply": "2026-07-19T23:20:57.019001Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0/8 topics complete · 0/8 resolved · agenda ~110 min\n", + "status: background=not_started, cx_strategy=not_started, channels=not_started, agent_environment=not_started, routing_automation=not_started, workforce_engagement=not_started, training=not_started, reporting_insights=not_started\n" + ] + } + ], + "source": [ + "# ── Session state (re-runs on any sidebar change) ───────────────────\n", + "# Read every widget .value and rebuild the session via the engine.\n", + "_LABEL_TO_STATUS = {STATUS_LABEL[s]: s for s in STATUSES}\n", + "\n", + "STATUS_BY_TOPIC = {k: _LABEL_TO_STATUS.get(str(w.value), STATUSES[0])\n", + " for k, w in _status_w.items()}\n", + "NOTES_BY_TOPIC = {k: str(w.value) for k, w in _notes_w.items()}\n", + "DONE_SUBTOPICS = {subtopic_id(tk, sk)\n", + " for (tk, sk), w in _sub_w.items() if bool(w.value)}\n", + "\n", + "SESSION = build_session(STATUS_BY_TOPIC, NOTES_BY_TOPIC, DONE_SUBTOPICS)\n", + "PROGRESS = SESSION[\"progress\"]\n", + "\n", + "# One curated line on stage; full echo backstage.\n", + "print(f\"{PROGRESS.label} · {PROGRESS.resolved}/{PROGRESS.total} resolved · \"\n", + " f\"agenda ~{SESSION['agenda_minutes']} min\")\n", + "backstage(\"status: \" + \", \".join(f\"{ts.key}={ts.status}\" for ts in SESSION[\"topics\"]))" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "cf857b6f", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:20:57.023448Z", + "iopub.status.busy": "2026-07-19T23:20:57.023214Z", + "iopub.status.idle": "2026-07-19T23:20:57.040484Z", + "shell.execute_reply": "2026-07-19T23:20:57.039569Z" + } + }, + "outputs": [ + { + "data": { + "application/mercury+json": { + "model_id": "cf76fb8741fe4e29ae6f8d1202443f99", + "position": "inline", + "widget": "MarkdownWidget" + }, + "application/vnd.jupyter.widget-view+json": { + "model_id": "cf76fb8741fe4e29ae6f8d1202443f99", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "MarkdownWidget(value='
'\n", + " f'
'\n", + " f'
'\n", + " f'
'\n", + " f'{completed} of {total} topics complete
')\n", + "\n", + "\n", + "def _topic_row(ts, is_active):\n", + " ring = f\"2px solid {BLUE}\" if is_active else f\"1px solid {HAIRLINE}\"\n", + " bg = \"#eef5fb\" if is_active else CARD_BG\n", + " active_tag = (f'discussing now →' if is_active else \"\")\n", + " sub = \"\"\n", + " if is_active and ts.subtopics_total:\n", + " items = []\n", + " for it in subtopic_checklist(_ACTIVE_TOPIC, DONE_SUBTOPICS):\n", + " mark = \"✓\" if it.done else \"○\"\n", + " col = GREEN if it.done else MUTED\n", + " wt = \"600\" if it.done else \"400\"\n", + " items.append(\n", + " f'
  • '\n", + " f'{mark}'\n", + " f'{esc(it.title)}
  • ')\n", + " sub = (f'
      '\n", + " f'{\"\".join(items)}
    ')\n", + " return (\n", + " f'
    '\n", + " f'
    '\n", + " f'{ts.glyph}'\n", + " f'{esc(ts.title)}'\n", + " f'{active_tag}'\n", + " f''\n", + " f'{esc(ts.status_label)}
    '\n", + " f'
    '\n", + " f'{esc(ts.scope)}
    '\n", + " f'{sub}
    ')\n", + "\n", + "\n", + "_ACTIVE_TOPIC = SESSION[\"active_topic\"]\n", + "_rows = \"\".join(_topic_row(ts, ts.key == SESSION[\"active_topic_key\"])\n", + " for ts in SESSION[\"topics\"])\n", + "_header = (\n", + " f'
    '\n", + " f'CX Discovery — topics
    '\n", + " f'
    '\n", + " f'{len(SESSION[\"topics\"])} topics · ~{SESSION[\"agenda_minutes\"]} minutes
    ')\n", + "\n", + "_board_html = (\n", + " f'
    {_header}'\n", + " f'{_progress_bar(PROGRESS.fraction, PROGRESS.completed, PROGRESS.total)}'\n", + " f'{_rows}
    ')\n", + "# Assign to _ so the bare-expression repr doesn't render a second copy.\n", + "_ = mr.Markdown(text=_board_html)" + ] + }, + { + "cell_type": "markdown", + "id": "0d679c91", + "metadata": {}, + "source": [ + "## Facilitator question script (backstage)\n", + "\n", + "The prompts below render in JupyterLab and in the exports — **not** on the\n", + "Mercury stage. They are your running order; ask them conversationally and let\n", + "the topics expand or drop as the client answers. Tick each sub-topic in the\n", + "sidebar as you cover it." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "a7d4ee27", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:20:57.042882Z", + "iopub.status.busy": "2026-07-19T23:20:57.042600Z", + "iopub.status.idle": "2026-07-19T23:20:57.048911Z", + "shell.execute_reply": "2026-07-19T23:20:57.047582Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "# CX Discovery — facilitation script\n", + "\n", + "\n", + "## Background & Organization · ~15 min\n", + "_Lines of business, channels, org structure, decision-making_\n", + "\n", + "\n", + "**Lines of business & scope** — `background.lines_of_business`\n", + " - How many distinct lines of business are supported in the contact centre? (e.g. commercial, residential, retail, wholesale)\n", + " - Are you using the contact centre for internal uses such as help desk, finance, HR?\n", + " - Payment card / PCI in scope?\n", + " - What are the availability SLAs or targets for your technology platform?\n", + "\n", + "**Channels supported** — `background.channels_supported`\n", + " - Which channels do you support today? (Apps, Voice, Video, Chat, SMS, Email, Social Media, Digital Assistants)\n", + "\n", + "**Org & reporting structure** — `background.org_structure`\n", + " - Mini org chart — reporting structure up to the executive leader.\n", + " - Are your contact centres managed by the same person? (Managers / Team Leads / Agents)\n", + " - Who carries the cost of contact centre agents and supervisors?\n", + " - What revenue is generated by the contact centre?\n", + "\n", + "**Decision-making & priorities** — `background.decision_making`\n", + " - Is decision-making centralized or decentralized?\n", + " - Who are the key decision makers for changes to the contact centre?\n", + " - How important is CX & EX to your organization's strategy? Is there an executive accountable for CX (CXO, CDO)?\n", + " - Of your leading offers, what is the customer's top priority?\n", + " - Competitive pressures?\n", + " - Any pending or recent acquisitions or spinoffs affecting IT infrastructure and services?\n", + "\n", + "**Problems & causes today** — `background.problems_today`\n", + " - What do you view as the problems in your contact centre today, and the primary causes?\n", + " - Any in-flight projects — CX or EX improvement initiatives?\n", + " - Are your customer experiences personalized?\n", + "\n", + "## CX Strategy · ~15 min\n", + "_How CX value is defined, measured, and organized to deliver_\n", + "\n", + "\n", + "**Value & strategic position** — `cx_strategy.value_definition`\n", + " - How is the value of Customer Experience defined within your organization? Is CX a key BPI, recognized & measured as a financial value?\n", + " - What are the key capabilities / services delivered by the contact centre?\n", + " - How are you using CX innovation to create market disruption?\n", + " - How are competitors using CX to create competitive differentiation?\n", + "\n", + "**Organization & operating model** — `cx_strategy.operating_model`\n", + " - Is there a CX team? Do the CX insights team regularly educate the business?\n", + " - Who are the key decision makers for investment and changes to the contact centre? Channel management strategy?\n", + " - What are the teams, and how are processes managed?\n", + " - Describe your automation strategy. Who is your leader for Data & AI?\n", + "\n", + "**Insight & Voice of Customer** — `cx_strategy.insight_and_voc`\n", + " - How do you use analytics & data to generate a consolidated view of your customer experience?\n", + " - Is there a VOC program in place? ROI / business value known?\n", + " - How do customers rate the experience they receive (0–5)?\n", + "\n", + "**Continuous improvement** — `cx_strategy.continuous_improvement`\n", + " - How is customer insight used to drive CX improvement, loyalty and profitability? How do you anticipate needs?\n", + " - Do you have a clear set of CX design guidelines? (Personas, Journey Mapping, Tools)\n", + " - KPI targets for CX — CSAT, NPS, CES? How are you doing?\n", + "\n", + "**Employee engagement** — `cx_strategy.employee_engagement`\n", + " - Describe your employee / agent engagement strategy.\n", + " - How engaged are your people in delivering the customer experience?\n", + " - Do you have a VoA / VoE program in place? How are you doing?\n", + "\n", + "## Channels · ~20 min\n", + "_Inbound & outbound volumes, metrics, contact reasons_\n", + "\n", + "\n", + "**Inbound context** — `channels.inbound_context`\n", + " - Hours of operation — any 24×7?\n", + " - Who contacts the contact centre? (Demographics, their situation)\n", + " - Are certain callers or groups prioritized?\n", + " - Languages? (English, Canadian French, Spanish, other)\n", + "\n", + "**Voice & video metrics** — `channels.voice_metrics`\n", + " - Average number of active agents (voice / video).\n", + " - Toll-free numbers & DIDs — approximate quantities.\n", + " - Average Wait Time, Abandon rate, Handle Time, Hold Time, After-call work time.\n", + " - Time to authenticate a caller.\n", + " - % of calls transferred — internally / externally (3rd parties)?\n", + " - Courtesy callback / virtual hold? Post-call survey? First Call Resolution rate? Average revenue per call (sales)?\n", + "\n", + "**Digital channels** — `channels.digital_channels`\n", + " - Email — range of logged-in users, response time, email server.\n", + " - Chat — web (internal/external), app-embedded, SMS, Messenger, WhatsApp, Telegram, iMessage.\n", + " - Website forms, mobile apps.\n", + "\n", + "**Inbound contact reasons** — `channels.inbound_reasons`\n", + " - Top 3–5 inbound contact reasons and approximate % of calls.\n", + " - Cost per call? Average Handle Time?\n", + " - Busiest / least busy days? Seasonal variances?\n", + " - Most difficult, commonly occurring calls? Easiest commonly occurring call?\n", + "\n", + "**Outbound** — `channels.outbound`\n", + " - Hours of operation.\n", + " - Voice (preview / predictive dialer volume), email, SMS, recorded announcement ports.\n", + " - Self-service applications, live agent connect, campaign management, DNC management.\n", + " - Top 3–5 outbound contact reasons and approximate % of calls.\n", + " - After-call work?\n", + "\n", + "## Agent & Supervisor Environment · ~10 min\n", + "_Locations, endpoints, desktop, applications, knowledge_\n", + "\n", + "\n", + "**Locations & endpoints** — `agent_environment.locations_endpoints`\n", + " - Location types — WFH / offices.\n", + " - Hard phone, soft phone, CODEC, wireless headset?\n", + " - Agent greeting / pre-recorded messages, whisper announcement.\n", + " - PC — desktop, laptop, VDI.\n", + "\n", + "**Desktop & applications** — `agent_environment.desktop_apps`\n", + " - Agent & supervisor desktop — omnichannel? Custom gadgets, screen pops, workflows.\n", + " - Standard browser? SSO?\n", + " - Applications used to handle calls.\n", + " - Knowledge Management.\n", + "\n", + "## Routing & Automation · ~15 min\n", + "_Self-service, IVR, speech, virtual agents, agent assist, RPA_\n", + "\n", + "\n", + "**Self-service & IVR** — `routing_automation.self_service`\n", + " - IVR persona — branding, style guides, voice actors?\n", + " - DTMF and/or speech? Speech recognition, TTS, NLU, voice biometrics.\n", + " - Self-service applications — ID & validate, deflection, situational offer (outage / time of day / scheduled).\n", + " - API integration (CRM). Intent capture, intent prediction, offer push on prediction / account attribute.\n", + "\n", + "**Virtual agents & assist** — `routing_automation.virtual_agents`\n", + " - Virtual agents — which processes?\n", + " - Agent assist?\n", + " - RPA?\n", + " - Current challenges or desired capabilities. Desire to automate. DevOps team?\n", + "\n", + "**Digital assistant apps** — `routing_automation.digital_assistants`\n", + " - Alexa, Google Assistant, Siri?\n", + "\n", + "## Workforce Engagement · ~20 min\n", + "_Call recording / QM, WFM, agent self-service, integrations_\n", + "\n", + "\n", + "**Call recording & Quality Management** — `workforce_engagement.recording_qm`\n", + " - How is call recording used? Compliance, screen capture, voice transcription (real-time?), desktop analytics, retention period.\n", + " - Quality team — who do they report to, how many people? Scorecards, score method & metrics, number of assessments, coaching, live monitor.\n", + " - Locations with call recording. Number of named agents.\n", + "\n", + "**Workforce management** — `workforce_engagement.workforce_management`\n", + " - Recruitment process, required qualifications, average tenure, attrition rate, internal moves.\n", + " - Do you measure agent & supervisor experience? Recognition program?\n", + " - Adherence measure — KPIs, gamification, shift length, breaks, annualized utilization %.\n", + " - Forecasting & scheduling — peak volume, historical data, algorithms, WFM interval (15/30 min).\n", + " - Intraday / real-time adherence — what happens when out of compliance?\n", + " - Payroll integration (ADP / Workday). Satisfaction with current tool(s)? Multiskilled agents, FTE calculations.\n", + "\n", + "**Agent self-service & integrations** — `workforce_engagement.agent_self_service`\n", + " - Agent self-service — absences, shift bids / swaps, performance metrics.\n", + " - Number of named agents.\n", + " - Integration to 3rd party — outsourcer / overflow, payroll.\n", + "\n", + "## Training · ~5 min\n", + "_Onboarding, format, assessment, eLearning, QM integration_\n", + "\n", + "\n", + "**Onboarding & enablement** — `training.onboarding`\n", + " - Onboarding process — how long, training format, assessment?\n", + " - eLearning?\n", + " - QM integration?\n", + "\n", + "## Reporting & Insights · ~10 min\n", + "_Real-time & historical reporting, analytics, BI, CRM_\n", + "\n", + "\n", + "**Reporting** — `reporting_insights.reporting`\n", + " - Real-time and historical — what are the key metrics you report on?\n", + " - Data source integration, dashboards, wallboards, agent & supervisor status.\n", + "\n", + "**Analytics & insights** — `reporting_insights.analytics_insights`\n", + " - Integrated view of customer details and contact history? CRM?\n", + " - Does the contact centre collect and use customer insight? Predictive engagement?\n", + " - What data analysis do you perform? Analytics / BI team — how many people? BI platform?\n", + " - Executive-level reporting? Marketing team interlock?\n" + ] + } + ], + "source": [ + "# ── Facilitator question script — backstage only ────────────────────\n", + "# Renders in JupyterLab and the exports; hidden on the Mercury stage.\n", + "_lines = [\"\\n# CX Discovery — facilitation script\\n\"]\n", + "for _t in TOPICS:\n", + " _lines.append(f\"\\n## {_t.title} · ~{_t.minutes} min\")\n", + " _lines.append(f\"_{_t.scope}_\\n\")\n", + " for _st in _t.subtopics:\n", + " _lines.append(f\"\\n**{_st.title}** — `{subtopic_id(_t.key, _st.key)}`\")\n", + " for _p in _st.prompts:\n", + " _lines.append(f\" - {_p}\")\n", + "backstage(\"\\n\".join(_lines))" + ] + }, + { + "cell_type": "markdown", + "id": "b5609e12", + "metadata": {}, + "source": [ + "## Verification & assertions\n", + "\n", + "Engine pins use explicit values independent of the sidebar, so the gate tests\n", + "`discoverylib`, not the current session; structural ties hold at **any** widget\n", + "state. This cell must pass under headless `nbconvert --execute` — it is the\n", + "study's smoke test. Output renders backstage only." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "0b8e617b", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:20:57.051159Z", + "iopub.status.busy": "2026-07-19T23:20:57.050927Z", + "iopub.status.idle": "2026-07-19T23:20:57.056852Z", + "shell.execute_reply": "2026-07-19T23:20:57.056059Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "All assertions passed.\n", + " 0/8 topics complete · 0/8 resolved\n" + ] + } + ], + "source": [ + "# ── Verification gate — must pass under headless nbconvert ───────────\n", + "def _assert(cond, msg):\n", + " assert cond, msg\n", + "\n", + "\n", + "# Engine shape — independent of widget state (Pattern §4)\n", + "_assert(len(TOPICS) == 8, \"expected 8 topics\")\n", + "_assert(sum(len(t.subtopics) for t in TOPICS) == 26, \"expected 26 sub-topics\")\n", + "_assert(SESSION[\"agenda_minutes\"] == 110, \"agenda minutes drifted\")\n", + "_assert(set(STATUS_BY_TOPIC) == {t.key for t in TOPICS}, \"status keys ≠ topics\")\n", + "\n", + "# Structural ties — hold at ANY sidebar setting\n", + "_p = SESSION[\"progress\"]\n", + "_assert(_p.total == len(SESSION[\"topics\"]) == 8, \"progress total ≠ topic count\")\n", + "_assert(_p.completed + _p.skipped + _p.in_progress + _p.not_started == _p.total,\n", + " \"status counts don't sum to total\")\n", + "_assert(0.0 <= _p.fraction <= 1.0, \"fraction out of range\")\n", + "_assert(_p.resolved == _p.completed + _p.skipped, \"resolved identity broke\")\n", + "for _ts in SESSION[\"topics\"]:\n", + " _assert(0 <= _ts.subtopics_done <= _ts.subtopics_total, \"sub-topic count out of range\")\n", + " _assert(_ts.status in STATUSES, f\"unknown status {_ts.status}\")\n", + "\n", + "# Export payload is plain-JSON serializable and consistent with the session\n", + "import json as _json\n", + "_payload = session_json(SESSION, meta={\"note\": \"gate check\"})\n", + "_json.dumps(_payload) # raises if not serializable\n", + "_assert(_payload[\"progress\"][\"completed\"] == _p.completed, \"export/session mismatch\")\n", + "_assert(len(_payload[\"topics\"]) == 8, \"export lost a topic\")\n", + "\n", + "backstage(\"All assertions passed.\")\n", + "backstage(f\" {_p.label} · {_p.resolved}/{_p.total} resolved\")" + ] + }, + { + "cell_type": "markdown", + "id": "8b2aceb5", + "metadata": {}, + "source": [ + "## Data appendix — for the machines\n", + "\n", + "The captured session as a markdown table plus one JSON block of state, so the\n", + "exported report is complete LLM input for drafting the survey write-up or\n", + "seeding a business-case study. Renders **backstage** — hidden on the Mercury\n", + "stage." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "c334037c", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-19T23:20:57.059694Z", + "iopub.status.busy": "2026-07-19T23:20:57.059500Z", + "iopub.status.idle": "2026-07-19T23:20:57.064010Z", + "shell.execute_reply": "2026-07-19T23:20:57.063460Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "#### Captured session\n", + "\n", + "| Topic | Status | Sub-topics | Notes |\n", + "|---|---|---:|---|\n", + "| Background & Organization | Not started | 0/5 | — |\n", + "| CX Strategy | Not started | 0/5 | — |\n", + "| Channels | Not started | 0/5 | — |\n", + "| Agent & Supervisor Environment | Not started | 0/2 | — |\n", + "| Routing & Automation | Not started | 0/3 | — |\n", + "| Workforce Engagement | Not started | 0/3 | — |\n", + "| Training | Not started | 0/1 | — |\n", + "| Reporting & Insights | Not started | 0/2 | — |\n", + "\n", + "0/8 topics complete · 0/8 resolved · agenda ~110 min\n", + "\n", + "\n", + "#### Session state (JSON)\n", + "\n", + "```json\n", + "{\n", + " \"study\": \"202607_CX_Discovery_Workshop\",\n", + " \"instrument\": \"CX Exploration & Discovery Workshop\",\n", + " \"meta\": {\n", + " \"client\": \"\",\n", + " \"date\": \"\",\n", + " \"facilitator\": \"\"\n", + " },\n", + " \"progress\": {\n", + " \"total_topics\": 8,\n", + " \"completed\": 0,\n", + " \"skipped\": 0,\n", + " \"in_progress\": 0,\n", + " \"not_started\": 8,\n", + " \"fraction_complete\": 0.0,\n", + " \"label\": \"0/8 topics complete\"\n", + " },\n", + " \"agenda_minutes\": 110,\n", + " \"active_topic\": \"background\",\n", + " \"topics\": [\n", + " {\n", + " \"key\": \"background\",\n", + " \"title\": \"Background & Organization\",\n", + " \"scope\": \"Lines of business, channels, org structure, decision-making\",\n", + " \"status\": \"not_started\",\n", + " \"minutes\": 15,\n", + " \"subtopics_done\": 0,\n", + " \"subtopics_total\": 5,\n", + " \"notes\": \"\"\n", + " },\n", + " {\n", + " \"key\": \"cx_strategy\",\n", + " \"title\": \"CX Strategy\",\n", + " \"scope\": \"How CX value is defined, measured, and organized to deliver\",\n", + " \"status\": \"not_started\",\n", + " \"minutes\": 15,\n", + " \"subtopics_done\": 0,\n", + " \"subtopics_total\": 5,\n", + " \"notes\": \"\"\n", + " },\n", + " {\n", + " \"key\": \"channels\",\n", + " \"title\": \"Channels\",\n", + " \"scope\": \"Inbound & outbound volumes, metrics, contact reasons\",\n", + " \"status\": \"not_started\",\n", + " \"minutes\": 20,\n", + " \"subtopics_done\": 0,\n", + " \"subtopics_total\": 5,\n", + " \"notes\": \"\"\n", + " },\n", + " {\n", + " \"key\": \"agent_environment\",\n", + " \"title\": \"Agent & Supervisor Environment\",\n", + " \"scope\": \"Locations, endpoints, desktop, applications, knowledge\",\n", + " \"status\": \"not_started\",\n", + " \"minutes\": 10,\n", + " \"subtopics_done\": 0,\n", + " \"subtopics_total\": 2,\n", + " \"notes\": \"\"\n", + " },\n", + " {\n", + " \"key\": \"routing_automation\",\n", + " \"title\": \"Routing & Automation\",\n", + " \"scope\": \"Self-service, IVR, speech, virtual agents, agent assist, RPA\",\n", + " \"status\": \"not_started\",\n", + " \"minutes\": 15,\n", + " \"subtopics_done\": 0,\n", + " \"subtopics_total\": 3,\n", + " \"notes\": \"\"\n", + " },\n", + " {\n", + " \"key\": \"workforce_engagement\",\n", + " \"title\": \"Workforce Engagement\",\n", + " \"scope\": \"Call recording / QM, WFM, agent self-service, integrations\",\n", + " \"status\": \"not_started\",\n", + " \"minutes\": 20,\n", + " \"subtopics_done\": 0,\n", + " \"subtopics_total\": 3,\n", + " \"notes\": \"\"\n", + " },\n", + " {\n", + " \"key\": \"training\",\n", + " \"title\": \"Training\",\n", + " \"scope\": \"Onboarding, format, assessment, eLearning, QM integration\",\n", + " \"status\": \"not_started\",\n", + " \"minutes\": 5,\n", + " \"subtopics_done\": 0,\n", + " \"subtopics_total\": 1,\n", + " \"notes\": \"\"\n", + " },\n", + " {\n", + " \"key\": \"reporting_insights\",\n", + " \"title\": \"Reporting & Insights\",\n", + " \"scope\": \"Real-time & historical reporting, analytics, BI, CRM\",\n", + " \"status\": \"not_started\",\n", + " \"minutes\": 10,\n", + " \"subtopics_done\": 0,\n", + " \"subtopics_total\": 2,\n", + " \"notes\": \"\"\n", + " }\n", + " ]\n", + "}\n", + "```\n" + ] + } + ], + "source": [ + "# ── Data appendix — LLM-readable dump of the captured session ───────\n", + "# Renders backstage only (JupyterLab / nbconvert exports).\n", + "import json as _json\n", + "\n", + "# Session metadata — edit these live for the client, or leave as defaults.\n", + "_META = {\n", + " \"client\": \"\", # 🟡 fill in for the engagement\n", + " \"date\": \"\", # 🟡 workshop date\n", + " \"facilitator\": \"\", # 🟡\n", + "}\n", + "\n", + "backstage(\"\\n#### Captured session\\n\")\n", + "_rows = [\"| Topic | Status | Sub-topics | Notes |\",\n", + " \"|---|---|---:|---|\"]\n", + "for _ts in SESSION[\"topics\"]:\n", + " _note = _ts.notes.replace(\"|\", \"\\\\|\").replace(\"\\n\", \" \") or \"—\"\n", + " _rows.append(f\"| {_ts.title} | {_ts.status_label} | \"\n", + " f\"{_ts.subtopics_done}/{_ts.subtopics_total} | {_note} |\")\n", + "backstage(\"\\n\".join(_rows))\n", + "\n", + "backstage(f\"\\n{PROGRESS.label} · {PROGRESS.resolved}/{PROGRESS.total} resolved \"\n", + " f\"· agenda ~{SESSION['agenda_minutes']} min\\n\")\n", + "\n", + "backstage(\"\\n#### Session state (JSON)\\n\")\n", + "backstage(\"```json\")\n", + "backstage(_json.dumps(session_json(SESSION, meta=_META), indent=2, ensure_ascii=False))\n", + "backstage(\"```\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.7" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "00b9b1239d634bc69d67508148b4d5df": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Background & Organization: Org & reporting structure", + "last_changed_at": "", + "layout": "IPY_MODEL_3582587d7a27431c8be9d3ffa024c89a", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "0a51d9b2d7ad4cd386911034dd9aecc5": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Routing & Automation: Digital assistant apps", + "last_changed_at": "", + "layout": "IPY_MODEL_435bc3967cff4beca08ca48f0fbb0e08", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "0ab5bbef78284ad0a011dcc2145a3850": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "0e24ed58f9b9415a90fe052a4e3342bf": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Training: Onboarding & enablement", + "last_changed_at": "", + "layout": "IPY_MODEL_e82e2575b84843408f189ddcc5d8ef7b", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "10c8be84f1804c86a5b938888f72c62a": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "Not started", + "In progress", + "Complete", + "Skipped" + ], + "disabled": false, + "hidden": false, + "label": "Background & Organization — status", + "layout": "IPY_MODEL_99c1f394d8574e71a04e6176d2d84f56", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Not started" + } + }, + "12a61c0a73aa4ae2ae27fcd72263c63b": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "15d0aa6ac0714e3685af841c84d13a48": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Routing & Automation: Virtual agents & assist", + "last_changed_at": "", + "layout": "IPY_MODEL_fa59fa350540437ab65cddd0b948f6b1", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "15e5250a35484ff0a4b5e5373d0527a0": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Agent & Supervisor Environment: Locations & endpoints", + "last_changed_at": "", + "layout": "IPY_MODEL_3e25e9ac4d99430ea90d49fcff188012", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "15e74d13d1f64de986496744c61d5c83": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "177b5301a0234fdf93277284006e5601": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "CX Strategy: Insight & Voice of Customer", + "last_changed_at": "", + "layout": "IPY_MODEL_3c56541c5ac947d580197bbc3b563f95", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "1d38c9ccfa4444deb04cf2fb46f91ec0": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "CX Strategy — notes", + "layout": "IPY_MODEL_43b4cb6836d04c4f8142a30162d0a0b5", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "" + } + }, + "20ce1fa7b06e4f86bb137706851bcf84": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "CX Strategy: Organization & operating model", + "last_changed_at": "", + "layout": "IPY_MODEL_2ec3c1ec05134ea684623d1d8ca06539", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "23a8c7e3fe9e4b8787f7fd1fb2064744": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "2881f086a4d14abab56d6508fcf62218": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "28bce7ca5a814f07a6276251f0521d8a": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Workforce Engagement — notes", + "layout": "IPY_MODEL_5be92f6bff24419a8d94e338c04d46b8", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "" + } + }, + "2ec3c1ec05134ea684623d1d8ca06539": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "2f744f3e85324a6c9c56a9c68c37d8af": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Routing & Automation: Self-service & IVR", + "last_changed_at": "", + "layout": "IPY_MODEL_365e451d9846410493eb519208cfb622", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "302c515cbf2f445a8e96a3e557dacfda": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "Not started", + "In progress", + "Complete", + "Skipped" + ], + "disabled": false, + "hidden": false, + "label": "Routing & Automation — status", + "layout": "IPY_MODEL_b7a69a28f88c4931a808d6d2e326c0f0", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Not started" + } + }, + "31b207b364744fa49b3c184e0a418ea9": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "34862dfebebd43c7a5705d7e63a166d6": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Workforce Engagement: Agent self-service & integrations", + "last_changed_at": "", + "layout": "IPY_MODEL_c39e774f768b45d78f9598309178ba62", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "3582587d7a27431c8be9d3ffa024c89a": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "365e451d9846410493eb519208cfb622": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "3c56541c5ac947d580197bbc3b563f95": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "3e25e9ac4d99430ea90d49fcff188012": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "3f9c462ee81646caaac03ebeb9055ae1": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "Not started", + "In progress", + "Complete", + "Skipped" + ], + "disabled": false, + "hidden": false, + "label": "Agent & Supervisor Environment — status", + "layout": "IPY_MODEL_4d8023b402724e7784ed8ee4b21947bc", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Not started" + } + }, + "430f1b8e205b4de7a3c54e8f3db18107": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Channels: Inbound contact reasons", + "last_changed_at": "", + "layout": "IPY_MODEL_23a8c7e3fe9e4b8787f7fd1fb2064744", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "435bc3967cff4beca08ca48f0fbb0e08": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "43b4cb6836d04c4f8142a30162d0a0b5": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "47a1106486e6494e90dfd0616fc7fc0f": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Background & Organization — notes", + "layout": "IPY_MODEL_50a99454ae3e4afdbca65b9f3ee89f7f", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "" + } + }, + "4951ecab2a9f4831b6e041a52fbb0884": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "4a36f1141ebc4915af04a7112b8210d3": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Reporting & Insights: Analytics & insights", + "last_changed_at": "", + "layout": "IPY_MODEL_71726fecf063433a9f4238fa2d128baa", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "4b2fd66370df42679080cb60015fbe3c": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Reporting & Insights — notes", + "layout": "IPY_MODEL_ed27b6ab00fb439bafd27011900a74b3", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "" + } + }, + "4d8023b402724e7784ed8ee4b21947bc": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "4dff1758d76c42e1a8fab271fe5b12c9": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "4e139491242c4e93a13081aca8905d20": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "Not started", + "In progress", + "Complete", + "Skipped" + ], + "disabled": false, + "hidden": false, + "label": "Workforce Engagement — status", + "layout": "IPY_MODEL_83561ff5a0204591b878c5a06b005077", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Not started" + } + }, + "5072fb8217314fbe9137e9d55ad9358d": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Background & Organization: Channels supported", + "last_changed_at": "", + "layout": "IPY_MODEL_621bea40095a4cef99638ef88d8143f3", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "50a99454ae3e4afdbca65b9f3ee89f7f": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "56b21c34e0234fc0b0d83fe950fca3a4": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "CX Strategy: Employee engagement", + "last_changed_at": "", + "layout": "IPY_MODEL_d305544e68144c3ab7b149512b6a568d", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "58daff561a724695ba1d32ba3771bd1e": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "Not started", + "In progress", + "Complete", + "Skipped" + ], + "disabled": false, + "hidden": false, + "label": "Channels — status", + "layout": "IPY_MODEL_97e1eeedec7248378d41ed0f9c1b7396", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Not started" + } + }, + "59e3152d6bde44f4bf75a8d88441b3ec": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Agent & Supervisor Environment — notes", + "layout": "IPY_MODEL_75b5b7a4336d4f889cd6ebf217a9d183", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "" + } + }, + "5be92f6bff24419a8d94e338c04d46b8": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "60ee47d42b1d4066877dec2b86577a01": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Background & Organization: Problems & causes today", + "last_changed_at": "", + "layout": "IPY_MODEL_7babb32651334fe68bacf11917a1da77", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "621bea40095a4cef99638ef88d8143f3": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "6580589f5f7b412f89671530df13090d": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Training — notes", + "layout": "IPY_MODEL_0ab5bbef78284ad0a011dcc2145a3850", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "" + } + }, + "6fa3e0db0dd3463993acc9c18ac10805": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Agent & Supervisor Environment: Desktop & applications", + "last_changed_at": "", + "layout": "IPY_MODEL_4dff1758d76c42e1a8fab271fe5b12c9", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "71726fecf063433a9f4238fa2d128baa": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "75b5b7a4336d4f889cd6ebf217a9d183": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "7792e81022c344b89b11a308207a6bbe": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Channels: Digital channels", + "last_changed_at": "", + "layout": "IPY_MODEL_7ad75e658e8747c6a4505f610dc4cc49", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "7ad75e658e8747c6a4505f610dc4cc49": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "7babb32651334fe68bacf11917a1da77": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "7d9b61e8dfaf472fabd6a2ce047d6729": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Background & Organization: Decision-making & priorities", + "last_changed_at": "", + "layout": "IPY_MODEL_dfe2dc69f8934f73b60c9f253afb3c08", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "83561ff5a0204591b878c5a06b005077": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "847e0e2f550344a6a78bc59767419338": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "8755ad066ef049a4beb4ca76d1fc08c6": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Routing & Automation — notes", + "layout": "IPY_MODEL_fa22be1733f348b69c788b81315f5fd1", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "" + } + }, + "8b204e5fca814a74874b84ceef255495": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "8e5fb4e5e45542e8a283674969277d5d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "8eaf41bd51594842a7ac8274d5f5f70b": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "900b88896e664a0c8c40a305da44ffb4": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "902b8644258e4e0394ab71de2de93fe6": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Workforce Engagement: Call recording & Quality Management", + "last_changed_at": "", + "layout": "IPY_MODEL_b08c18e82f4947b3a96da2211bd7f433", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "97e1eeedec7248378d41ed0f9c1b7396": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "9831e05d2a98408b9b4072ff81aef0cd": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "Not started", + "In progress", + "Complete", + "Skipped" + ], + "disabled": false, + "hidden": false, + "label": "Reporting & Insights — status", + "layout": "IPY_MODEL_2881f086a4d14abab56d6508fcf62218", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Not started" + } + }, + "99c1f394d8574e71a04e6176d2d84f56": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "9adb705fc7cc420da7965276388fafe8": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "Not started", + "In progress", + "Complete", + "Skipped" + ], + "disabled": false, + "hidden": false, + "label": "CX Strategy — status", + "layout": "IPY_MODEL_31b207b364744fa49b3c184e0a418ea9", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Not started" + } + }, + "9deaa72bbf0948988dfdb57bcf670f40": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Channels: Outbound", + "last_changed_at": "", + "layout": "IPY_MODEL_12a61c0a73aa4ae2ae27fcd72263c63b", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "add2dcc4edde499581741451b25b7559": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Channels: Inbound context", + "last_changed_at": "", + "layout": "IPY_MODEL_900b88896e664a0c8c40a305da44ffb4", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "b08c18e82f4947b3a96da2211bd7f433": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "b715b892818b46019201b5a688f70dcf": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "CX Strategy: Value & strategic position", + "last_changed_at": "", + "layout": "IPY_MODEL_f970d4839d8f4511ab9e995f0da3e706", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "b784c44f81fd4663b94098ffe046af71": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Reporting & Insights: Reporting", + "last_changed_at": "", + "layout": "IPY_MODEL_15e74d13d1f64de986496744c61d5c83", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "b7a69a28f88c4931a808d6d2e326c0f0": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "c39e774f768b45d78f9598309178ba62": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "cb06370551d3496ca2e374ed62bf6620": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Workforce Engagement: Workforce management", + "last_changed_at": "", + "layout": "IPY_MODEL_4951ecab2a9f4831b6e041a52fbb0884", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "cda4056ee6f1451696fbd29c12b8f3f7": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "cf76fb8741fe4e29ae6f8d1202443f99": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "cell_id": "", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_847e0e2f550344a6a78bc59767419338", + "layout_path": null, + "placeholder": "​", + "position": "inline", + "render_slot_id": null, + "source_cell_id": null, + "style": "IPY_MODEL_ec1be2c8173343f6b2829c950f4bffc8", + "tabbable": null, + "tooltip": null, + "value": "
    CX Discovery — topics
    8 topics · ~110 minutes
    0 of 8 topics complete
    Background & Organizationdiscussing now →Not started
    Lines of business, channels, org structure, decision-making
    • Lines of business & scope
    • Channels supported
    • Org & reporting structure
    • Decision-making & priorities
    • Problems & causes today
    CX StrategyNot started
    How CX value is defined, measured, and organized to deliver
    ChannelsNot started
    Inbound & outbound volumes, metrics, contact reasons
    Agent & Supervisor EnvironmentNot started
    Locations, endpoints, desktop, applications, knowledge
    Routing & AutomationNot started
    Self-service, IVR, speech, virtual agents, agent assist, RPA
    Workforce EngagementNot started
    Call recording / QM, WFM, agent self-service, integrations
    TrainingNot started
    Onboarding, format, assessment, eLearning, QM integration
    Reporting & InsightsNot started
    Real-time & historical reporting, analytics, BI, CRM
    " + } + }, + "d1318d0516724e41b98ac4bc97d5501f": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.select.SelectWidget", + "_css": "\n .mljar-select-container {\n position: relative;\n display: flex;\n flex-direction: column;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n overflow: visible;\n }\n\n .mljar-select-label {\n padding-top: 6px;\n margin-bottom: 4px;\n font-weight: 600;\n }\n\n .mljar-select-control {\n position: relative;\n display: flex;\n align-items: center;\n cursor: default;\n overflow: visible;\n }\n\n .mljar-select-container.is-open {\n z-index: 20;\n }\n\n .mljar-select-widget-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 36px 9px 10px;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-sizing: border-box;\n line-height: 1.4;\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\n\n appearance: none !important;\n background-color: #ffffff !important;\n color: #0f172a !important;\n cursor: default;\n }\n\n .mljar-select-widget-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n cursor: text;\n }\n\n .mljar-select-caret {\n position: absolute;\n right: 12px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 1.5px solid #0f172a;\n border-bottom: 1.5px solid #0f172a;\n transform: translateY(-65%) rotate(45deg);\n pointer-events: auto;\n opacity: 0.5;\n transition: transform 0.18s ease, opacity 0.18s ease;\n }\n\n .mljar-select-container.is-open .mljar-select-caret {\n opacity: 1;\n transform: translateY(-35%) rotate(225deg);\n }\n\n .mljar-select-dropdown {\n display: none;\n position: fixed;\n z-index: 10000;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);\n overflow: hidden;\n }\n\n .mljar-select-list {\n max-height: 260px;\n overflow-y: auto;\n }\n\n .mljar-select-option {\n display: block;\n width: 100%;\n padding: 9px 10px;\n border: 0;\n background: transparent;\n color: #0f172a;\n text-align: left;\n cursor: pointer;\n font: inherit;\n transition: background-color 0.14s ease, color 0.14s ease;\n }\n\n .mljar-select-option:hover {\n background: #f3f3f4;\n }\n\n .mljar-select-option:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-option.is-selected {\n background: #e6f2ff;\n color: #007bff;\n font-weight: 600;\n }\n\n .mljar-select-option.is-selected:hover,\n .mljar-select-option.is-selected:active {\n background: #e6f2ff;\n color: #007bff;\n }\n\n .mljar-select-empty {\n display: none;\n padding: 10px;\n color: #616673;\n font-size: 0.95em;\n }\n\n .mljar-select-widget-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n .mljar-select-control.is-disabled .mljar-select-caret {\n opacity: 0.45;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const normalize = value => String(value ?? \"\").toLowerCase().trim();\n const getChoices = () =>\n Array.isArray(model.get(\"choices\")) ? [...model.get(\"choices\")] : [];\n const isDisabled = () => !!model.get(\"disabled\");\n const isHidden = () => !!model.get(\"hidden\");\n\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-select-container\");\n\n if (model.get(\"label\")) {\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-select-label\");\n topLabel.innerHTML = model.get(\"label\");\n container.appendChild(topLabel);\n }\n\n const control = document.createElement(\"div\");\n control.classList.add(\"mljar-select-control\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-select-widget-input\");\n input.autocomplete = \"off\";\n input.spellcheck = false;\n\n const caret = document.createElement(\"div\");\n caret.classList.add(\"mljar-select-caret\");\n\n control.appendChild(input);\n control.appendChild(caret);\n\n const dropdown = document.createElement(\"div\");\n dropdown.classList.add(\"mljar-select-dropdown\");\n\n const list = document.createElement(\"div\");\n list.classList.add(\"mljar-select-list\");\n\n const emptyState = document.createElement(\"div\");\n emptyState.classList.add(\"mljar-select-empty\");\n emptyState.textContent = \"No matches\";\n\n dropdown.appendChild(list);\n dropdown.appendChild(emptyState);\n\n container.appendChild(control);\n el.appendChild(container);\n\n let isOpen = false;\n let filteredChoices = [];\n let lastCommittedValue = \"\";\n let isEditing = false;\n document.body.appendChild(dropdown);\n\n const updateDropdownPosition = () => {\n if (!isOpen) {\n return;\n }\n const rect = control.getBoundingClientRect();\n dropdown.style.top = `${rect.bottom + 6}px`;\n dropdown.style.left = `${rect.left}px`;\n dropdown.style.width = `${rect.width}px`;\n };\n\n const setOpen = next => {\n if (isDisabled()) {\n isOpen = false;\n } else {\n isOpen = !!next;\n }\n container.classList.toggle(\"is-open\", isOpen);\n dropdown.style.display = isOpen ? \"block\" : \"none\";\n if (isOpen) {\n updateDropdownPosition();\n }\n };\n\n const updateDisabledState = () => {\n const disabled = isDisabled();\n input.disabled = disabled;\n control.classList.toggle(\"is-disabled\", disabled);\n };\n\n const updateHiddenState = () => {\n container.style.display = isHidden() ? \"none\" : \"\";\n };\n\n const syncInputWithValue = () => {\n const value = model.get(\"value\") || \"\";\n lastCommittedValue = value;\n if (!isEditing) {\n input.value = value;\n }\n };\n\n const filterChoices = query => {\n const normalizedQuery = normalize(query);\n const allChoices = getChoices();\n if (!normalizedQuery) {\n return allChoices;\n }\n return allChoices.filter(choice =>\n normalize(choice).includes(normalizedQuery)\n );\n };\n\n const renderList = () => {\n list.innerHTML = \"\";\n filteredChoices.forEach(choice => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.classList.add(\"mljar-select-option\");\n if (choice === model.get(\"value\")) {\n option.classList.add(\"is-selected\");\n }\n option.textContent = choice;\n option.addEventListener(\"mousedown\", event => {\n event.preventDefault();\n event.stopPropagation();\n model.set(\"value\", choice);\n model.save_changes();\n isEditing = false;\n syncInputWithValue();\n renderList();\n setOpen(false);\n });\n list.appendChild(option);\n });\n\n const hasMatches = filteredChoices.length > 0;\n list.style.display = hasMatches ? \"block\" : \"none\";\n emptyState.style.display = hasMatches ? \"none\" : \"block\";\n };\n\n const refreshList = () => {\n filteredChoices = filterChoices(input.value);\n renderList();\n };\n\n const openWithCurrentQuery = () => {\n isEditing = true;\n input.value = \"\";\n refreshList();\n setOpen(true);\n };\n\n const closeDropdown = () => {\n isEditing = false;\n setOpen(false);\n input.value = lastCommittedValue;\n };\n\n control.addEventListener(\"click\", event => {\n event.stopPropagation();\n if (isDisabled()) {\n return;\n }\n if (event.target === caret && isOpen) {\n closeDropdown();\n input.blur();\n return;\n }\n openWithCurrentQuery();\n input.focus();\n });\n\n input.addEventListener(\"input\", () => {\n if (isDisabled()) {\n return;\n }\n refreshList();\n setOpen(true);\n });\n\n input.addEventListener(\"focus\", () => {\n if (isDisabled()) {\n return;\n }\n openWithCurrentQuery();\n });\n\n input.addEventListener(\"blur\", () => {\n isEditing = false;\n input.value = lastCommittedValue;\n });\n\n const handleDocumentClick = event => {\n if (!container.contains(event.target) && !dropdown.contains(event.target)) {\n closeDropdown();\n }\n };\n\n document.addEventListener(\"click\", handleDocumentClick);\n window.addEventListener(\"resize\", updateDropdownPosition);\n document.addEventListener(\"scroll\", updateDropdownPosition, true);\n\n model.on(\"change:value\", () => {\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:choices\", () => {\n const choices = getChoices();\n if (!choices.includes(model.get(\"value\")) && choices.length > 0) {\n model.set(\"value\", choices[0]);\n model.save_changes();\n return;\n }\n syncInputWithValue();\n refreshList();\n });\n\n model.on(\"change:disabled\", () => {\n updateDisabledState();\n if (isDisabled()) {\n closeDropdown();\n }\n });\n\n model.on(\"change:hidden\", () => {\n updateHiddenState();\n });\n\n updateDisabledState();\n updateHiddenState();\n syncInputWithValue();\n refreshList();\n setOpen(false);\n\n return () => {\n dropdown.remove();\n document.removeEventListener(\"click\", handleDocumentClick);\n window.removeEventListener(\"resize\", updateDropdownPosition);\n document.removeEventListener(\"scroll\", updateDropdownPosition, true);\n };\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "choices": [ + "Not started", + "In progress", + "Complete", + "Skipped" + ], + "disabled": false, + "hidden": false, + "label": "Training — status", + "layout": "IPY_MODEL_8b204e5fca814a74874b84ceef255495", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "Not started" + } + }, + "d305544e68144c3ab7b149512b6a568d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d9f9a188dd4f48f7a30fcb41e78e8257": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Channels: Voice & video metrics", + "last_changed_at": "", + "layout": "IPY_MODEL_8eaf41bd51594842a7ac8274d5f5f70b", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "dfe2dc69f8934f73b60c9f253afb3c08": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e74f98220a094696b7e2525782c140d0": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Background & Organization: Lines of business & scope", + "last_changed_at": "", + "layout": "IPY_MODEL_8e5fb4e5e45542e8a283674969277d5d", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + }, + "e82e2575b84843408f189ddcc5d8ef7b": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ec1be2c8173343f6b2829c950f4bffc8": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "ed27b6ab00fb439bafd27011900a74b3": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f1920f6a825349f1be5e9cd1a22b0708": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.text.TextInputWidget", + "_css": "\n .mljar-textinput-container {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n width: 100%;\n min-width: 120px;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n font-weight: normal;\n color: #0f172a;\n padding-left: 4px;\n padding-right: 4px;\n box-sizing: border-box;\n }\n\n .mljar-textinput-top-label {\n padding-top: 6px;\n margin-bottom: 6px;\n text-align: left;\n width: 100%;\n font-weight: 600;\n }\n\n .mljar-textinput-input {\n width: 100%;\n min-height: 40px;\n padding: 9px 10px;\n box-sizing: border-box;\n border: 1px solid #cfd1d5;\n border-radius: 6px;\n background: #ffffff;\n color: #0f172a;\n line-height: 1.4;\n\n appearance: none !important;\n background-color: #ffffff !important;\n }\n\n .mljar-textinput-input:focus {\n outline: none;\n border-color: #007bff;\n box-shadow: none;\n }\n\n .mljar-textinput-input:disabled {\n background: #f5f5f5;\n color: #888;\n cursor: not-allowed;\n }\n\n @media (max-width: 768px) {\n .mljar-textinput-input {\n min-height: 44px;\n padding: 10px 12px;\n }\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"div\");\n container.classList.add(\"mljar-textinput-container\");\n\n const topLabel = document.createElement(\"div\");\n topLabel.classList.add(\"mljar-textinput-top-label\");\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.classList.add(\"mljar-textinput-input\");\n\n container.appendChild(topLabel);\n container.appendChild(input);\n el.appendChild(container);\n\n let debounceTimer = null;\n\n input.addEventListener(\"input\", () => {\n if (model.get(\"disabled\")) return;\n model.set(\"value\", input.value);\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => model.save_changes(), 200);\n });\n\n function syncFromModel() {\n topLabel.innerHTML = model.get(\"label\") || \"Enter text\";\n input.value = model.get(\"value\") ?? \"\";\n\n const disabled = !!model.get(\"disabled\");\n input.disabled = disabled;\n\n const hidden = !!model.get(\"hidden\");\n container.style.display = hidden ? \"none\" : \"flex\";\n }\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n /*\n // ---- read cell id (no DOM modifications) ----\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "Channels — notes", + "layout": "IPY_MODEL_cda4056ee6f1451696fbd29c12b8f3f7", + "layout_path": null, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": "" + } + }, + "f2fc5e48221a411794915f937f7ba4b2": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f970d4839d8f4511ab9e995f0da3e706": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fa22be1733f348b69c788b81315f5fd1": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fa59fa350540437ab65cddd0b948f6b1": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fe8ea7220e28420aa3f4b8901b51a2d9": { + "model_module": "anywidget", + "model_module_version": "~0.11.*", + "model_name": "AnyModel", + "state": { + "_anywidget_id": "mercury.checkbox.CheckboxWidget", + "_css": "\n .mljar-checkbox-container {\n display: inline-flex;\n align-items: center;\n gap: 10px;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n font-family: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n color: #0f172a;\n padding-left: 5px;\n }\n .mljar-checkbox-container.is-disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .mljar-checkbox-input {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n }\n\n .mljar-checkbox-input:focus-visible + .mljar-checkbox-control {\n box-shadow: inset 0 0 0 2px #007bff;\n }\n\n .mljar-checkbox-label {\n font-size: 14px;\n line-height: 1.2;\n padding-top: 2px;\n }\n\n /* --- Toggle style (15% smaller) --- */\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control {\n position: relative;\n width: 34px;\n height: 19px;\n border-radius: 999px;\n background: #f1f1f2;\n border: 1px solid #cfd1d5;\n transition: background 150ms ease, border-color 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control {\n background: #007bff;\n border-color: #007bff;\n }\n .mljar-checkbox-container.is-toggle .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 15px;\n height: 15px;\n border-radius: 50%;\n background: #ffffff;\n box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 0 0 1px rgba(0,0,0,0.04);\n transition: transform 150ms ease;\n }\n .mljar-checkbox-container.is-toggle.is-checked .mljar-checkbox-control::after {\n transform: translateX(15px);\n }\n\n /* --- Classic box style --- */\n .mljar-checkbox-container.is-box .mljar-checkbox-control {\n width: 16px;\n height: 16px;\n border-radius: 4px;\n border: 1px solid #cfd1d5;\n background: #ffffff;\n display: inline-block;\n position: relative;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control {\n border-color: #007bff;\n background: #007bff;\n }\n .mljar-checkbox-container.is-box.is-checked .mljar-checkbox-control::after {\n content: \"\";\n position: absolute;\n left: 4px;\n top: 0px;\n width: 5px;\n height: 10px;\n border: solid #fff;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .mljar-checkbox-container:not(.is-disabled):hover .mljar-checkbox-control {\n border-color: #007bff;\n background: #f3f3f4;\n }\n ", + "_dom_classes": [], + "_esm": "\n function render({ model, el }) {\n const container = document.createElement(\"label\");\n container.classList.add(\"mljar-checkbox-container\");\n\n const input = document.createElement(\"input\");\n input.type = \"checkbox\";\n input.classList.add(\"mljar-checkbox-input\");\n\n const control = document.createElement(\"span\");\n control.classList.add(\"mljar-checkbox-control\");\n\n const text = document.createElement(\"span\");\n text.classList.add(\"mljar-checkbox-label\");\n\n container.appendChild(input);\n container.appendChild(control);\n container.appendChild(text);\n el.appendChild(container);\n\n function syncFromModel() {\n // appearance\n const a = model.get(\"appearance\") || \"toggle\";\n container.classList.remove(\"is-toggle\",\"is-box\");\n container.classList.add(`is-${a}`);\n input.setAttribute(\"role\", a === \"toggle\" ? \"switch\" : \"checkbox\");\n\n // value\n const v = !!model.get(\"value\");\n if (input.checked !== v) {\n input.checked = v;\n input.setAttribute(\"aria-checked\", String(v));\n }\n container.classList.toggle(\"is-checked\", v);\n\n // disabled\n const d = !!model.get(\"disabled\");\n input.disabled = d;\n container.classList.toggle(\"is-disabled\", d);\n\n // label\n text.textContent = model.get(\"label\") || \"\";\n\n // hidden (exists but not visible)\n container.style.display = model.get(\"hidden\") ? \"none\" : \"inline-flex\";\n }\n\n input.addEventListener(\"change\", () => {\n if (model.get(\"disabled\")) return;\n\n const v = input.checked;\n if (model.get(\"value\") !== v) {\n model.set(\"value\", v);\n model.set(\"last_changed_at\", new Date().toISOString());\n model.set(\"n_toggles\", (model.get(\"n_toggles\") || 0) + 1);\n model.save_changes();\n // model.send({ type: \"changed\", value: v });\n }\n });\n\n model.on(\"change:value\", syncFromModel);\n model.on(\"change:disabled\", syncFromModel);\n model.on(\"change:appearance\", syncFromModel);\n model.on(\"change:label\", syncFromModel);\n model.on(\"change:hidden\", syncFromModel);\n\n syncFromModel();\n\n // ---- read cell id (no DOM modifications) ----\n /*\n const ID_ATTR = \"data-cell-id\";\n const hostWithId = el.closest(`[${ID_ATTR}]`);\n const cellId = hostWithId ? hostWithId.getAttribute(ID_ATTR) : null;\n\n if (cellId) {\n model.set(\"cell_id\", cellId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: cellId });\n } else {\n const mo = new MutationObserver(() => {\n const host = el.closest(`[${ID_ATTR}]`);\n const newId = host?.getAttribute(ID_ATTR);\n \n if (newId) {\n model.set(\"cell_id\", newId);\n model.save_changes();\n model.send({ type: \"cell_id_detected\", value: newId });\n mo.disconnect();\n }\n });\n mo.observe(document.body, { attributes: true, subtree: true, attributeFilter: [ID_ATTR] });\n }\n */\n }\n export default { render };\n ", + "_model_module": "anywidget", + "_model_module_version": "~0.11.*", + "_model_name": "AnyModel", + "_view_count": null, + "_view_module": "anywidget", + "_view_module_version": "~0.11.*", + "_view_name": "AnyView", + "appearance": "box", + "cell_id": "", + "disabled": false, + "hidden": false, + "label": "CX Strategy: Continuous improvement", + "last_changed_at": "", + "layout": "IPY_MODEL_f2fc5e48221a411794915f937f7ba4b2", + "layout_path": null, + "n_toggles": 0, + "position": "sidebar", + "render_slot_id": null, + "source_cell_id": null, + "tabbable": null, + "tooltip": null, + "url_key": "", + "value": false + } + } + }, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/studies/202607_CX_Discovery_Workshop/pyproject.toml b/studies/202607_CX_Discovery_Workshop/pyproject.toml new file mode 100644 index 0000000..e9ec9f9 --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/pyproject.toml @@ -0,0 +1,35 @@ +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[project] +name = "discoverylib" +version = "0.1.0" +description = "CX Exploration & Discovery Workshop — live facilitation aid (Mercury Notebook Pattern)" +requires-python = ">=3.10" +# The notebook is the deliverable (served with Mercury, exported via +# nbconvert, tables via tabulate) — the whole toolchain is a required +# runtime dependency, not an extra. `pip install -e .` must be enough. +dependencies = [ + "pandas>=2.0", + "plotly>=5.18", + "mercury>=3.2", + "jupyterlab>=4.0", + "ipywidgets>=8.0", + "nbconvert>=7", + "tabulate>=0.9", +] + +[project.optional-dependencies] +dev = ["pytest>=7.4", "mypy>=1.8"] + +[tool.setuptools.packages.find] +include = ["discoverylib*"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "-q" + +[tool.mypy] +strict = true +packages = ["discoverylib"] diff --git a/studies/202607_CX_Discovery_Workshop/scripts/build_notebook.py b/studies/202607_CX_Discovery_Workshop/scripts/build_notebook.py new file mode 100644 index 0000000..71edfae --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/scripts/build_notebook.py @@ -0,0 +1,362 @@ +"""Generate notebooks/cx_discovery.ipynb from source cell text. + +The discovery notebook has ~42 Mercury widgets (a status selector + a notes +box per topic, plus a checkbox per sub-topic). Hand-maintaining that JSON is +error-prone, so the notebook is *generated* from this script — the cell +sources live here as readable Python strings and nbformat writes valid JSON. + +Re-run after editing any cell: python scripts/build_notebook.py +Then execute + export as usual (nbconvert / scripts/export_report.py). + +This is a build tool, not the engine — all study logic stays in discoverylib. +""" + +from __future__ import annotations + +import pathlib + +import nbformat as nbf + +ROOT = pathlib.Path(__file__).resolve().parent.parent +OUT = ROOT / "notebooks" / "cx_discovery.ipynb" + + +# ── Cell sources ───────────────────────────────────────────────────── + +MD_TITLE = """\ +# CX Exploration & Discovery Workshop + +The live visual for a discovery session. On screen the client sees the +**topic board** — each topic, its one-line scope, and a status glyph — the +**live sub-topic checklist** for whatever we're discussing now, and a +**progress headline** ("3/8 topics complete"). You drive the conversation +from the question script (which stays backstage); the client is never shown +a wall of questions. + +**This notebook is the deliverable.** Serve it with +`mercury --working-dir .` and share that screen; mark each topic's status in +the sidebar as the discussion moves and tick sub-topics as you cover them — +the board and progress bar update live. Capture answers in the per-topic +notes boxes. Afterward, `python scripts/export_report.py` writes an +LLM-readable report source (notes + status + progress as markdown and JSON) +to feed the survey write-up or a downstream business-case study. + +All content and logic live in `discoverylib/` — the notebook only arranges +and renders them. + +Confidence legend: 🟢 confirmed · 🟡 estimated · 🔴 unknown — used in the +captured notes, not on the client-facing board.""" + + +SETUP = '''\ +# ── Setup ────────────────────────────────────────────────────────── +import sys, pathlib +_ROOT = pathlib.Path.cwd() +if not (_ROOT / "discoverylib").exists(): # notebook lives in notebooks/ + _ROOT = _ROOT.parent +sys.path.insert(0, str(_ROOT)) + +import html as _html + +import mercury as mr + +# Single source of truth — the topic bank and all status/progress logic +# live in the library; only presentation (and Mercury widgets) lives here. +from discoverylib import ( + TOPICS, STATUSES, STATUS_LABEL, STATUS_GLYPH, STATUS_COLOR, + build_session, subtopic_checklist, subtopic_id, session_json, +) +from discoverylib.staging import backstage + +# ── Brand palette (docs/brand.md, light theme) ───────────────────── +NAVY, INK, MUTED = "#151d2c", "#2e404d", "#586671" +BLUE, GREEN, LINE = "#0072bc", "#00a34c", "#e2e6e9" +CARD_BG, HAIRLINE = "#f8f8f8", "#d5d9db" +FONT = "Georgia, 'Times New Roman', serif" +BODY_FONT = "Arial, 'Helvetica Neue', Helvetica, sans-serif" + + +def esc(s): + return _html.escape(str(s)) + + +backstage(f"discoverylib loaded — {len(TOPICS)} topics · " + f"{sum(len(t.subtopics) for t in TOPICS)} sub-topics · " + f"{sum(t.prompt_count for t in TOPICS)} prompts")''' + + +MD_HOWTO = """\ +## How to run this session + +- **Sidebar** — one **status** selector and a **notes** box per topic, plus a + **sub-topic checkbox** for each thread. As the conversation moves, set the + topic you're on to *In progress*, tick sub-topics as you cover them, mark + the topic *Complete* (or *Skipped*) when you move on, and jot answers in its + notes box. +- **Stage** (this page) — the client-facing board and progress bar below + re-render on every change. +- **Backstage** (JupyterLab / the export) — the facilitator question script and + the captured-notes appendix. Neither shows on the Mercury stage.""" + + +# The widget block is generated from the topic bank so it stays DRY and +# can never drift from discoverylib. Widgets ONLY — no other output +# (Mercury leaks stray widget-cell output into the sidebar). +WIDGETS = '''\ +# ── Session controls (Mercury sidebar — widgets ONLY, no other output) ─ +# Generated from the topic bank: per topic a status selector + notes box, +# per sub-topic a checkbox. Mercury re-runs only cells BELOW this one, so +# every .value is read in the next cell down — never here. +# +# _status_w[topic_key] -> Select (Not started / In progress / …) +# _notes_w[topic_key] -> TextInput (captured answers, backstage) +# _sub_w[(topic_key, sub)] -> CheckBox (covered?) +# Labels are distinct per widget, so Mercury's label-keyed widget cache +# never collides across topics/sub-topics. +_status_w, _notes_w, _sub_w = {}, {}, {} + +for _t in TOPICS: + _status_w[_t.key] = mr.Select( + label=f"{_t.title} — status", + value=STATUS_LABEL[STATUSES[0]], + choices=[STATUS_LABEL[s] for s in STATUSES], + ) + for _st in _t.subtopics: + _sub_w[(_t.key, _st.key)] = mr.CheckBox( + value=False, appearance="box", + label=f"{_t.title}: {_st.title}") + _notes_w[_t.key] = mr.TextInput( + label=f"{_t.title} — notes", value="")''' + + +STATE = '''\ +# ── Session state (re-runs on any sidebar change) ─────────────────── +# Read every widget .value and rebuild the session via the engine. +_LABEL_TO_STATUS = {STATUS_LABEL[s]: s for s in STATUSES} + +STATUS_BY_TOPIC = {k: _LABEL_TO_STATUS.get(str(w.value), STATUSES[0]) + for k, w in _status_w.items()} +NOTES_BY_TOPIC = {k: str(w.value) for k, w in _notes_w.items()} +DONE_SUBTOPICS = {subtopic_id(tk, sk) + for (tk, sk), w in _sub_w.items() if bool(w.value)} + +SESSION = build_session(STATUS_BY_TOPIC, NOTES_BY_TOPIC, DONE_SUBTOPICS) +PROGRESS = SESSION["progress"] + +# One curated line on stage; full echo backstage. +print(f"{PROGRESS.label} · {PROGRESS.resolved}/{PROGRESS.total} resolved · " + f"agenda ~{SESSION['agenda_minutes']} min") +backstage("status: " + ", ".join(f"{ts.key}={ts.status}" for ts in SESSION["topics"]))''' + + +# The client-facing board. Pure HTML string built from SESSION; rendered +# with mr.Markdown so it shows on the Mercury stage (and in exports). +BOARD = '''\ +# ── Stage: the client-facing topic board + progress ───────────────── +def _progress_bar(frac, completed, total): + pct = max(0.0, min(1.0, frac)) * 100 + return ( + f'
    ' + f'
    ' + f'
    ' + f'
    ' + f'{completed} of {total} topics complete
    ') + + +def _topic_row(ts, is_active): + ring = f"2px solid {BLUE}" if is_active else f"1px solid {HAIRLINE}" + bg = "#eef5fb" if is_active else CARD_BG + active_tag = (f'discussing now →' if is_active else "") + sub = "" + if is_active and ts.subtopics_total: + items = [] + for it in subtopic_checklist(_ACTIVE_TOPIC, DONE_SUBTOPICS): + mark = "✓" if it.done else "○" + col = GREEN if it.done else MUTED + wt = "600" if it.done else "400" + items.append( + f'
  • ' + f'{mark}' + f'{esc(it.title)}
  • ') + sub = (f'
      ' + f'{"".join(items)}
    ') + return ( + f'
    ' + f'
    ' + f'{ts.glyph}' + f'{esc(ts.title)}' + f'{active_tag}' + f'' + f'{esc(ts.status_label)}
    ' + f'
    ' + f'{esc(ts.scope)}
    ' + f'{sub}
    ') + + +_ACTIVE_TOPIC = SESSION["active_topic"] +_rows = "".join(_topic_row(ts, ts.key == SESSION["active_topic_key"]) + for ts in SESSION["topics"]) +_header = ( + f'
    ' + f'CX Discovery — topics
    ' + f'
    ' + f'{len(SESSION["topics"])} topics · ~{SESSION["agenda_minutes"]} minutes
    ') + +_board_html = ( + f'
    {_header}' + f'{_progress_bar(PROGRESS.fraction, PROGRESS.completed, PROGRESS.total)}' + f'{_rows}
    ') +# Assign to _ so the bare-expression repr doesn't render a second copy. +_ = mr.Markdown(text=_board_html)''' + + +MD_SCRIPT = """\ +## Facilitator question script (backstage) + +The prompts below render in JupyterLab and in the exports — **not** on the +Mercury stage. They are your running order; ask them conversationally and let +the topics expand or drop as the client answers. Tick each sub-topic in the +sidebar as you cover it.""" + + +SCRIPT = '''\ +# ── Facilitator question script — backstage only ──────────────────── +# Renders in JupyterLab and the exports; hidden on the Mercury stage. +_lines = ["\\n# CX Discovery — facilitation script\\n"] +for _t in TOPICS: + _lines.append(f"\\n## {_t.title} · ~{_t.minutes} min") + _lines.append(f"_{_t.scope}_\\n") + for _st in _t.subtopics: + _lines.append(f"\\n**{_st.title}** — `{subtopic_id(_t.key, _st.key)}`") + for _p in _st.prompts: + _lines.append(f" - {_p}") +backstage("\\n".join(_lines))''' + + +MD_GATE = """\ +## Verification & assertions + +Engine pins use explicit values independent of the sidebar, so the gate tests +`discoverylib`, not the current session; structural ties hold at **any** widget +state. This cell must pass under headless `nbconvert --execute` — it is the +study's smoke test. Output renders backstage only.""" + + +GATE = '''\ +# ── Verification gate — must pass under headless nbconvert ─────────── +def _assert(cond, msg): + assert cond, msg + + +# Engine shape — independent of widget state (Pattern §4) +_assert(len(TOPICS) == 8, "expected 8 topics") +_assert(sum(len(t.subtopics) for t in TOPICS) == 26, "expected 26 sub-topics") +_assert(SESSION["agenda_minutes"] == 110, "agenda minutes drifted") +_assert(set(STATUS_BY_TOPIC) == {t.key for t in TOPICS}, "status keys ≠ topics") + +# Structural ties — hold at ANY sidebar setting +_p = SESSION["progress"] +_assert(_p.total == len(SESSION["topics"]) == 8, "progress total ≠ topic count") +_assert(_p.completed + _p.skipped + _p.in_progress + _p.not_started == _p.total, + "status counts don't sum to total") +_assert(0.0 <= _p.fraction <= 1.0, "fraction out of range") +_assert(_p.resolved == _p.completed + _p.skipped, "resolved identity broke") +for _ts in SESSION["topics"]: + _assert(0 <= _ts.subtopics_done <= _ts.subtopics_total, "sub-topic count out of range") + _assert(_ts.status in STATUSES, f"unknown status {_ts.status}") + +# Export payload is plain-JSON serializable and consistent with the session +import json as _json +_payload = session_json(SESSION, meta={"note": "gate check"}) +_json.dumps(_payload) # raises if not serializable +_assert(_payload["progress"]["completed"] == _p.completed, "export/session mismatch") +_assert(len(_payload["topics"]) == 8, "export lost a topic") + +backstage("All assertions passed.") +backstage(f" {_p.label} · {_p.resolved}/{_p.total} resolved")''' + + +MD_APPENDIX = """\ +## Data appendix — for the machines + +The captured session as a markdown table plus one JSON block of state, so the +exported report is complete LLM input for drafting the survey write-up or +seeding a business-case study. Renders **backstage** — hidden on the Mercury +stage.""" + + +APPENDIX = '''\ +# ── Data appendix — LLM-readable dump of the captured session ─────── +# Renders backstage only (JupyterLab / nbconvert exports). +import json as _json + +# Session metadata — edit these live for the client, or leave as defaults. +_META = { + "client": "", # 🟡 fill in for the engagement + "date": "", # 🟡 workshop date + "facilitator": "", # 🟡 +} + +backstage("\\n#### Captured session\\n") +_rows = ["| Topic | Status | Sub-topics | Notes |", + "|---|---|---:|---|"] +for _ts in SESSION["topics"]: + _note = _ts.notes.replace("|", "\\\\|").replace("\\n", " ") or "—" + _rows.append(f"| {_ts.title} | {_ts.status_label} | " + f"{_ts.subtopics_done}/{_ts.subtopics_total} | {_note} |") +backstage("\\n".join(_rows)) + +backstage(f"\\n{PROGRESS.label} · {PROGRESS.resolved}/{PROGRESS.total} resolved " + f"· agenda ~{SESSION['agenda_minutes']} min\\n") + +backstage("\\n#### Session state (JSON)\\n") +backstage("```json") +backstage(_json.dumps(session_json(SESSION, meta=_META), indent=2, ensure_ascii=False)) +backstage("```")''' + + +def md(source: str) -> nbf.NotebookNode: + return nbf.v4.new_markdown_cell(source) + + +def code(source: str) -> nbf.NotebookNode: + return nbf.v4.new_code_cell(source) + + +def build() -> nbf.NotebookNode: + nb = nbf.v4.new_notebook() + nb.cells = [ + md(MD_TITLE), + code(SETUP), + md(MD_HOWTO), + code(WIDGETS), + code(STATE), + code(BOARD), + md(MD_SCRIPT), + code(SCRIPT), + md(MD_GATE), + code(GATE), + md(MD_APPENDIX), + code(APPENDIX), + ] + nb.metadata = { + "kernelspec": {"display_name": "Python 3", "language": "python", + "name": "python3"}, + "language_info": {"name": "python"}, + } + return nb + + +def main() -> None: + OUT.parent.mkdir(parents=True, exist_ok=True) + nbf.write(build(), OUT) + print(f"wrote {OUT.relative_to(ROOT)} ({len(build().cells)} cells)") + + +if __name__ == "__main__": + main() diff --git a/studies/202607_CX_Discovery_Workshop/scripts/export_report.py b/studies/202607_CX_Discovery_Workshop/scripts/export_report.py new file mode 100644 index 0000000..5c4dbaa --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/scripts/export_report.py @@ -0,0 +1,48 @@ +"""Export the discovery notebook as an LLM-readable report source. + +Executes the notebook fresh (widget defaults — or whatever you've captured and +saved in the notebook), then writes both formats to exports/: + + exports/cx_discovery.html — human-reviewable + exports/cx_discovery.md — leanest LLM input + +The client-facing board is HTML the export carries, but the machine payload — +every topic's status, sub-topic tally, and captured notes — lives in the +backstage data-appendix cell (markdown table + JSON), so the exported `.md` is +complete input for drafting the survey write-up or seeding a business case. + +Run from the study root: python scripts/export_report.py +""" +from __future__ import annotations + +import subprocess +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +NOTEBOOKS = [ + ROOT / "notebooks" / "cx_discovery.ipynb", +] +EXPORTS = ROOT / "exports" + + +def main() -> None: + picked = [nb for nb in NOTEBOOKS + if len(sys.argv) < 2 or sys.argv[1] in nb.name] + if not picked: + sys.exit(f"no notebook matches {sys.argv[1]!r}") + EXPORTS.mkdir(exist_ok=True) + for nb in picked: + for fmt in ("html", "markdown"): + subprocess.run( + [sys.executable, "-m", "nbconvert", "--execute", + "--to", fmt, "--output-dir", str(EXPORTS), str(nb)], + check=True, cwd=ROOT, + ) + for p in sorted(EXPORTS.iterdir()): + if p.suffix in (".html", ".md"): + print(f"wrote {p.relative_to(ROOT)} ({p.stat().st_size / 1024:,.0f} KB)") + + +if __name__ == "__main__": + main() diff --git a/studies/202607_CX_Discovery_Workshop/tests/conftest.py b/studies/202607_CX_Discovery_Workshop/tests/conftest.py new file mode 100644 index 0000000..faed9ad --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/tests/conftest.py @@ -0,0 +1,7 @@ +"""Make discoverylib importable even without the study venv active (the +normal setup is ``pip install -e ".[dev]"`` into the study-local ``.venv/``).""" + +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent)) diff --git a/studies/202607_CX_Discovery_Workshop/tests/test_session.py b/studies/202607_CX_Discovery_Workshop/tests/test_session.py new file mode 100644 index 0000000..a23f42c --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/tests/test_session.py @@ -0,0 +1,117 @@ +"""Session engine pins — status, progress, checklist, and export payload. + +Progress and status are this study's "numbers"; these are the hand-checked +acceptance values the in-notebook gate re-pins (Pattern §4). +""" + +from discoverylib import ( + COMPLETE, + IN_PROGRESS, + NOT_STARTED, + SKIPPED, + TOPIC_KEYS, + active_topic_key, + build_session, + normalize_status, + progress, + session_json, + subtopic_checklist, + subtopic_id, + topic, +) + + +def test_normalize_status_defaults_unknown(): + assert normalize_status("complete") == COMPLETE + assert normalize_status(None) == NOT_STARTED + assert normalize_status("garbage") == NOT_STARTED + + +def test_progress_all_not_started(): + p = progress({}) + assert p.total == 8 + assert (p.completed, p.skipped, p.in_progress, p.not_started) == (0, 0, 0, 8) + assert p.fraction == 0.0 + assert p.resolved == 0 + assert p.label == "0/8 topics complete" + + +def test_progress_mixed_counts_and_fraction(): + status = { + "background": COMPLETE, + "cx_strategy": COMPLETE, + "channels": IN_PROGRESS, + "agent_environment": SKIPPED, + # remaining four default to not_started + } + p = progress(status) + assert (p.completed, p.skipped, p.in_progress, p.not_started) == (2, 1, 1, 4) + assert p.resolved == 3 # complete + skipped + assert p.fraction == 2 / 8 + assert p.label == "2/8 topics complete" + + +def test_active_topic_prefers_in_progress_then_first_open(): + # in-progress wins even if a later topic is also in progress + assert active_topic_key({"channels": IN_PROGRESS}) == "channels" + # no in-progress → first not-started in canonical order + assert active_topic_key({"background": COMPLETE}) == "cx_strategy" + # everything resolved → None + all_done = {k: COMPLETE for k in TOPIC_KEYS} + assert active_topic_key(all_done) is None + + +def test_subtopic_checklist_marks_done(): + t = topic("channels") + done = {subtopic_id("channels", "voice_metrics")} + items = subtopic_checklist(t, done) + assert len(items) == len(t.subtopics) + by_key = {i.key: i.done for i in items} + assert by_key["voice_metrics"] is True + assert by_key["inbound_context"] is False + + +def test_build_session_shape_and_subtopic_done_count(): + status = {"channels": IN_PROGRESS, "background": COMPLETE} + notes = {"channels": " 6 channels; voice ~70% "} + done = {subtopic_id("channels", "voice_metrics"), + subtopic_id("channels", "outbound")} + s = build_session(status, notes, done) + + assert len(s["topics"]) == 8 + assert s["active_topic_key"] == "channels" + assert s["active_topic"].title == "Channels" + assert s["agenda_minutes"] == 110 + + ch = next(ts for ts in s["topics"] if ts.key == "channels") + assert ch.status == IN_PROGRESS + assert ch.subtopics_done == 2 + assert ch.subtopics_total == len(topic("channels").subtopics) + assert ch.notes == "6 channels; voice ~70%" # trimmed + + bg = next(ts for ts in s["topics"] if ts.key == "background") + assert bg.status == COMPLETE and bg.subtopics_done == 0 + + +def test_session_json_is_plain_and_complete(): + status = {"background": COMPLETE, "channels": IN_PROGRESS} + notes = {"background": "3 LOBs; PCI in scope"} + done = {subtopic_id("channels", "voice_metrics")} + payload = session_json(build_session(status, notes, done), + meta={"client": "Acme", "date": "2026-07-19"}) + + assert payload["study"] == "202607_CX_Discovery_Workshop" + assert payload["meta"]["client"] == "Acme" + assert payload["progress"]["completed"] == 1 + assert payload["progress"]["fraction_complete"] == round(1 / 8, 4) + assert payload["active_topic"] == "channels" + assert len(payload["topics"]) == 8 + bg = next(t for t in payload["topics"] if t["key"] == "background") + assert bg["status"] == COMPLETE + assert bg["notes"] == "3 LOBs; PCI in scope" + ch = next(t for t in payload["topics"] if t["key"] == "channels") + assert ch["subtopics_done"] == 1 + + # JSON-serializable (no dataclasses / sets leaked through) + import json + json.dumps(payload) diff --git a/studies/202607_CX_Discovery_Workshop/tests/test_staging.py b/studies/202607_CX_Discovery_Workshop/tests/test_staging.py new file mode 100644 index 0000000..63ff857 --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/tests/test_staging.py @@ -0,0 +1,15 @@ +"""Stage/backstage detection — Mercury kernels carry MERCURY_CONFIG_DIR.""" + +from discoverylib import staging + + +def test_backstage_prints_only_off_stage(monkeypatch, capsys): + monkeypatch.delenv("MERCURY_CONFIG_DIR", raising=False) + assert not staging.on_stage() + staging.backstage("visible") + assert capsys.readouterr().out == "visible\n" + + monkeypatch.setenv("MERCURY_CONFIG_DIR", "/tmp/app") + assert staging.on_stage() + staging.backstage("hidden") + assert capsys.readouterr().out == "" diff --git a/studies/202607_CX_Discovery_Workshop/tests/test_topics.py b/studies/202607_CX_Discovery_Workshop/tests/test_topics.py new file mode 100644 index 0000000..f318196 --- /dev/null +++ b/studies/202607_CX_Discovery_Workshop/tests/test_topics.py @@ -0,0 +1,62 @@ +"""Topic bank integrity — the verbatim facilitation record. + +These pins are the anchor guard (Pattern §4): keys are stable identities +that captured notes and the JSON export key off, so renaming or reordering a +topic must be a deliberate, test-breaking act — never a silent drift. +""" + +from discoverylib import TOPICS, TOPIC_KEYS, topic +from discoverylib.topics import TOPIC_BY_KEY + + +# ── Hand-checked shape (recount if you add/remove content) ─────────── +def test_topic_count_and_order(): + assert len(TOPICS) == 8 + assert TOPIC_KEYS == ( + "background", + "cx_strategy", + "channels", + "agent_environment", + "routing_automation", + "workforce_engagement", + "training", + "reporting_insights", + ) + + +def test_subtopic_and_prompt_totals(): + assert sum(len(t.subtopics) for t in TOPICS) == 26 + assert sum(t.prompt_count for t in TOPICS) == 95 + + +def test_agenda_minutes_sum(): + from discoverylib import agenda_minutes + assert agenda_minutes() == 110 + assert agenda_minutes() == sum(t.minutes for t in TOPICS) + + +# ── Structural invariants — hold for every topic ───────────────────── +def test_keys_unique_and_wellformed(): + keys = [t.key for t in TOPICS] + assert len(keys) == len(set(keys)) # unique + for t in TOPICS: + assert t.key.replace("_", "").isalnum() # snake_case slug + assert t.title and t.scope # client-facing text present + assert t.minutes > 0 + assert t.subtopics # no empty topic + sub_keys = [st.key for st in t.subtopics] + assert len(sub_keys) == len(set(sub_keys)) # unique within topic + for st in t.subtopics: + assert st.prompts # no empty sub-topic + + +def test_lookup_helpers(): + assert topic("channels").title == "Channels" + assert TOPIC_BY_KEY["training"].minutes == 5 + assert TOPICS[0].key == "background" + + +def test_no_double_dollar_or_raw_markup_in_scope(): + # scope lines render on stage HTML — keep them plain text. + for t in TOPICS: + assert "<" not in t.scope and ">" not in t.scope