Files
design-v3/iteration-3/screens/index.html
T
Joshua KingandClaude Opus 5 d9ed1898b9 Add the Extrudex Design System v3 bundle
Tokens (light + dark, neumorphism, 54/54 WCAG AA contrast pairs), the
self-hosted JetBrains Mono fonts, and interactive mockups of every screen
across three iterations. Iteration 3 is final: phone, tablet and desktop
tiers, device preview, and "empty spool weight" terminology. The build
scripts regenerate the screens byte-identically from source.

Implementation is tracked in Maestro feature UI Refresh - V3.0
(224b72a1-8d84-4970-97ea-5dafa4d8ea3b).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 11:31:50 -04:00

1513 lines
265 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Extrudex Flow Map</title>
<meta name="description" content="How the iteration-2 screens connect, with guided flows.">
<script>
(function () { var t = null; try { t = localStorage.getItem('extrudex-v3-theme'); } catch (e) {}
var q = /[?&]theme=(light|dark)/.exec(location.search); if (q) t = q[1];
if (t !== 'light' && t !== 'dark') t = window.matchMedia && matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', t); })();
</script>
<style>
/*
* CubeCraftLabs Design System v3 (proposal): Soft UI / Neumorphism
*
* Built on Design System v2.0 (http://pages.ccl/design-v2.0/, verified
* identical to Extrudex web/src/theme.css at dev 321ce0d on 2026-09-18).
*
* Structure
* 1. Font faces JetBrains Mono, self-hosted woff2, no CDN
* 2. v2.0 base scale kept verbatim, so v2 references still resolve
* 3. v3 theme tokens dark (default, as in v2.0) and light (new)
* 4. Neumorphism surfaces, raised/inset shadow pairs, intensity, radius
* 5. State tokens focus, pressed, disabled, error
* 6. Reference components used by the mockups
*
* Accessibility rules this file enforces:
* - Shadows are decoration. Every control also has a border at 3:1 or more
* against its surface (WCAG 1.4.11), so it stays visible with shadows off.
* - Focus, pressed, disabled and error each change something besides shadow
* direction: the outline, the fill plus a check glyph, a dashed border, or
* a red border plus an icon plus a message.
* - The contrast table is in design-system-v3.md.
*
* Theme selection: dark is the default because v2.0 is dark. Light applies
* when the OS prefers it and nothing is forced, or with data-theme="light" on
* <html>. data-theme="dark" forces dark.
*/
/* ── 1. Font faces ──────────────────────────────────────────────────────── */
/* The same files @fontsource/jetbrains-mono 5.3.0 ships (the app's dependency). */
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-display: swap; font-weight: 400; src: url('data:font/woff2;base64,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') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-display: swap; font-weight: 500; src: url('data:font/woff2;base64,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') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-display: swap; font-weight: 700; src: url('data:font/woff2;base64,d09GMgABAAAAAFWUABAAAAAA4YQAAFUvAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoEOG4ZWHIGacgZgP1NUQVRMAIUiEQgKgdwYgaswC4YWAAE2AiQDjBoEIAWEaAejDAwHG+rEBxi3PxTdCahV976Zq6yAHXsBnIdgEh7vgpkRYeOAALTMsv//bwl0jB2scUzTCLHIcDWadPM5lEzpW+XG3shNhUkRC3nEu7P/dUyEMIWAgyoxRfKXKoNIAIFaR9M7km25siI3Jjssy/pp06G7W7fk8CUrh7cysuUMHVUskd6ReqaSGRj+yDveiLaHO706qHXVdryd/qRFyhv6rozhq0lYT8x0MVBuyzFknZf8gX9P/9ybiCQNIiIU1YiINCIiTYk0jVQzVc3Cssw8Nf0Rn6GqqqmhmWVKaqaoqpn6TdXMM9WfZ6qq+llnambmeZbneWamZoalqsnw5Kb/NNOsobgQVHAg846trGOcCIgyBVFQQbbCocYkoLtGk21MUzPmb1a32rXSlfXTJB3apCuxM7Njp4X/7/erd+1zLr/XzQMogz0TAjX4hUxFIVpSH1yrXz7gImQ0lg/bfJWKQuohopatZ1+hUDqXx2IRDoukPBIjKVTMPoSs8dhj2fnmepuUMIATGgwA7H7itkLVmROmr0IdCGHQ3h2uqbmmx3ngpgNGO+GA3azr0LoCFxqfVKX4Rp8VTszt79OZP2MZ3tuRLEOIqeKdXZ11dxEkcRAcqZFb+3cHFCCfPzBXwd81f3JNqzdlSKix8bP6gbDAScoQuFK47S+UzZoEwT/30xf703LCRdgmpxyRAxKmSgODpfODo3m9/1grgJv8E+Zfp/6v90p2q7Kd9AHxsDTvA8Ay0xVZcKValtXWEHQKclJw4oJD51lW3GM7zuHzjtsPTI5d4Bd4wLh9YDr7H4aZedhWGqbvf5pZpsBv4Pb1YCFH+ZaxkQsvdi3vUx9kH9PonSG7m/w7wJIjzzNyPj7TO+e4HJkh7/zIWV4SqZReGgieam/L9iv+VPUQyuNCNi5L/9ncyza1Q3ZYJMgQkrSpPPmyOnXGnt+r1o6Q5DWxSmVh36Mt/KyRBywZmdDFXKY0f+aC1kvRQHdVC1DUzbtJXmlxFWqC/9DDg+DNmRYz3r3WzKGHMUEIIYxTrtVnDwvWMjJUgt6kLyiGDc1wGPPBWxMNY2aTfpc2yXchnG6WRQizGGGE8be2rVmT0LZgjWBfiBL83euG/X7VomPzyubRNtWkKSkiAgoKCiXa3Hft7v1SBQQAEgAAACiOEPAgEGFD4OBA4AqRhJxCEmE0klDSSSKSVRIxbJKI1SSJZH5JpIpI4hRMEqetk8Rf/oJgYoIoQQnMUaKSmKP3lc4caZXDHOXrQzAgABBhEkDPLinUsOyVJ7PSYRlYAOA1ipndMWAhAIiMNbgpf0aYyfiAWiUkksuwjfEYALqPOlcOA491ipI43TCc2LVQQNtHG1pNP08D0vcIIgxfLOQHc04nQ+cA5HvNoIK8Kfk00xSAfKORyqeA+alWtQQEIWaPDwv16Y661A4g79uDAmCnBYZbgCgJcOoIoFCWn/OFkO0lHDpJnndLAUgp3oEKPwAW2B+ybOCnJYCTiPlQutqxA9Jf8i9hFLLTkBkMWSfxpDdZSIpJKakkVaSerCJtZC3ZQDaSiS2TLAMg7sBoVWUcgkkogKGHyQAQc2CWw0myjYrD3zm4foAlkkWwGESwVcJ+oieQqrQPHfdZ5QTOSffhue+R3MGp3B4XenqspoP7xM9BOpB3F4F9QTBYFSQWYhyo8BgiG8Y9/WRqFkgmj6dlAO9d8v/H4hTAmpodT4USTA6NU0C+D9MDqOI3AgDDj7/xYgUBW+w5cORkK1fuGJi8cXDxCOwSZDepEAqoClp6BiYWNnWcGnj4BIS0wrRZZ6OEbgX0zjMo8amLKl1Wo9ZVTVq0atPun7rcckePb9w3aMgTzwwb8YNxk/7jF//1P3PmLVryp1V/2/A6gLhlSqrqNdSEQmeCXAjBBCKpXKXRGUwWm4MTMnJKKDUNHb1qRmZWNrXqODUQ3XLQXFGqvqX+WP2+2qpW58D3y18oP8XeLguAfo1eQzeiDegK1W8qkSpfeUX5gtKj1Ci+VlxTvKswK1AS35Xfkp+TK+UwY0LOIs8ix5BU2T+ymKxBmveu7J09HW+iXpq9N0lmki2EfoqXS7QyquxVsOlYFJwDjYsoXR7NQXUQSll7bu2p3VMqmZOMSeK3K8ra3b+7McUi1wDxtHhQLBHzfqkP6gvqhH6Ky2aGqEtUKUID58PGWj/GjyrO1WAeFgOKAtJ7cz+7a3yXqpcdWMIWYeXOjXbxZ/3O3DZ9UW4VAlMzLSgRZNYT/n3+YTWP38/v2FPK5/Cd9/1Bb/Uz+Ln4AW+lKOVlFQwelYfzrfLV72umUn3Rfc0lSVlUupLOZk+KIpUiGoqHOd2ej8hEumNxx+SOoh3ZMWUHlr0e1bHL2AVsCvvH4uthvXehN41lCopY2Ub4rNfTwHvyUC5MYDPMEWYcU9BAJz3732KxVEkWGBOMY0S9RQh4rBxYHqk4Dvo5tyS6GS2jEnoOYtNtt/dub9uu8uV+gPuo+x33ME/8oOc8bJvfNrwt100vVhyzs7ivOSvXSdlLXTfseQPRtvxqyOh36eCkUhfurvGtvVvbXOKt7L2c7zi3xPKd3Z06nGr3XDkJnJxpjbRKWiGN5mjSChwzNKAu7Sml5qup/JvjsKlMO6QrkbKRMkBRyUL7Tvs6WqG92J5O7iRX0QrJclFgZ7SH7Vy7Y3ZE2+W8Ln/MlmyzbjVbBsuFtGm2mWWmlMTc0k1VJN/CIfbeidbXlI1PmK6DNbNGVxx+sdQUXWHjba17c2OWWjNxo+lO0iRF3IjGmBFVEbDfhXA3ucl7vMzLPNdFGA7GDTUe2RcILhQaIghYLsBwxTnJ2IKjuKjJM7wQTgLdz96kLytUmG8HSVmDi6IwEVkVgQqB9+1BgLxKEnZfVF0WsAvIV/Cld5kxq4VxWNEbWb8SlCW243UnKtBH0utjFeq8itydbpAZHgCP1BcHptQJpMQD8gLJoBMQBESR4IF89cneYvWRkN/XF8ky/C9ahk4qU6eUpdPKZj4AWDJZFbMF46vy4hz0HMkgdWKw7KTAZzF2YiOBM2lZhrJZ0MaqEihU3HVAkqH0RT+MG/donSRw8SIkgUZOblQiGr6f4sWaao2BDwnBQj8lAHK2BOTSLfLTMalLL8y4tK4+/WHzOUi+FMo1Ypw9ouc//w3AJ0gCM/j/d4gJf+7a4w1ZEUeDh4n8uMP5B4BeOkQ3HhNPTjn/bcU2IDZXB9DzG6W3bhQg82Wxb8Gc81/QPv3ADb8g+o8vBG0HmqZHnRP+B2fT7Zqh4DmJO9VDke4lJFMPBVHEG23Rb+hM8YJPBv/p8OcGpVCtBhzc2zmgUA+3DQ6oOoGr26Iv1dlwkY+drnNRRTkekeyQV3muydqVQLhztugZdh53vH9mdraRb68GcgBD7lVk/t+6I7euZh3NHpROpgbIYCWXJC2clrp7hysv4embdbbcrUn7S40KIKmO76ItrG4f8DAWIGHCW2/r04t0Hm/O7OTpn1OBA/LCpGQeCIwJsqlXAToQsuwZEyDj6RHwuZudut0GyEqdREcGyIa9JN0aVIpIYtuij9F5EkVj9t+nX/XRjKKskIdv+pjNN9/KU/M8tRH5dEn8f1ex+O1jXgELDnjXztAXnK77dsR8wT4rbV8j8j6ms9sOzGOfiPeNgMK6vbZ4VAa/G+yjMsqubYthRKckDTaP730eV8CCYC+vds5ObHfvp2khR81yfRU93bDDVAh7//NRALMtCR6nvXdyXYRuU4JbHS4malzGNuyaXHUbN/ZakwJzi61NmuhG5K1GZzdhsPtqXMZW57ZjdI0Tpt8izTW2HNmktj5Dip3GMyuveRkbt1qX6zq6xLET65SrDXQpx1oZX2ebS6zLx2u3/zEi0jqtC9C10T8SDtk1NrDmu5pG5zhyfI0151hjpFqxderD7exqxqyixgZWkVspdIpDn1/BnGKlyrJk69Nj7bxl2uybNTewDFVLPV9ERxzCsZS4iklHOQTI+IpsjlgMx0t8uUlEWrS6CF1U5QIKrxprmBdd2Uk79kFf1pkd82MpS4zI8x07u8yFPVBjDfOom3W0Yo/2c7pZMXfIHGvrM9TZaQqz4TXXMB+pZlveKM3YZjFtuKKPZtlGZHzRZmbMzONplFdFG6Oj6D+jUz9Pb8Pxpj+mGRZA7kZbGrHF+WHTjAB0GRYakQFZaZjE0yMCdkvp8OcUUISANyS3cajHuug3Z9Pj9bxsuEbk1xPaWNdRCrE6btX6eN3qivWiVUW+mLWt0ksx2hZ9ljaKAZQgvc4RJXc5uagV02dmWyu6ZIu26Ml2dsjF1AbZY1tYEMsK0jgnLWagO/BwN9KAW5TSoTxcv4xf5JhDpBpWFppEplREhZ6zUO9IR+8WTUHnPhzUuKSgBR7m+iQ2CxxkV4nt88+01Jq5cyPzQZQ2Eh4p6nPTHXL83zgyOekIsGDcKI+vDrzf52NtPLo486orv+xXuHWyROe6DTu0RzHxz/UrwF9W5zuL4wFQG/cK0YCnG9YSfZnlqt1sXXRTjRlGSZUV+MB+uCclS8clixTKZJbxyYQJMcJxFpoMEpGGJV2EZkJOVxDrWdOMoaNqAziZxDHpy5ZRxBV8nmHAhhuOIfO42UgCaKGPqCOfq5nnMJk+Au8XQJdZNa0BdKIY19FUuoFEVMYZGN+bDC27gGVqP0tE6phiPnZMP1pIazahna2SiV3lBVZJSAZdn1/gudqATTEYbetxUrsriojUVunf0MSwS45XOM8AXYPvjrq6ao+1x8jDMJdbJQPkyzC6jG/FxkMdu2hZiEh1uJZoS82Ik+jO+wH/QjwmjZEGha3ic/NMgcKZR8r45o6xEVcvmmZEpLhQS7Qpz5hFQNHD+UWNKKECPpYyXbeLNbLKfubb4QCqXcj3uYA2okaXMqzZdftDzy7LxlmTjHOONnV2g0+FjimKtaXGM9RPKyHDW0IGeiWEWBeyyZBevOEaqDQG6tJjQegNabdE56rcTxcYrCVBhPOI88XfBDZ6vDcZzDBAGroBD0aMCtDHfIdlACh1B9N3GCrTAtQh4hCUYtUkRv94VAKMfFQdDqhJRif0IMTIqAyvAXyvzY0q51ycqhSb4d0EdOKpHgXu3BLwZglZbwMS0d5CSHG8jD5L21jG81zzGTxJggU5kYlHaYkGE446ULojc8HzgDYCnO6CRvqIVuiDMvMRbPOFQX7ZlnpxN/29Aj21ExfE8fTPtBkoI+gwHbS6C2A1nMRyA71H0w5W6AI8vZOmegN21bwDi2OFG9N6dwoqdIMP30urv55YO+84c6eKN5qjsC57XLye02R81m1eg06xwq1PZKJPqdCT3DQ6S7pGIEGrqiyGVtFL1K3IQh0toBdSV5bxNN2+UDGSub+cljpMhUlGygjO7K3hh3RCKNUGhaBYJYUCimdzCowni0ZAWrsgE4hIqUFLlAxlzEK8lu8shFTNdiT7C7Bwt1pJZUxI7gTMUpU2XH0SL4MZqTMfYaht/TscFZoZIRXydSSrzCbhJ7NbOGAP3tojN8+VRE0KbMkKkaS3ycP0BXuvViorvG5JLR6jrITNJVquGL79qAwQ/OxR8Wo+lXB9+xbA4+mK3+cDNtEI3BjDpcxNS0yiykmcHKdF1ngb6Zwkbu8UE3iJMgUJfpKOTsAkZZTh6vt4GUxI2yQ2vmzbM12tqiUezsjdYUkdmYoXEk0DWkcxXxJ5EUlrUow1YCV2TbGFuMlpqWmKJoSYEVw4X8MfsbMkOTQo/lIaJBoXY4uVuaqMj5bNCqIpSaRyIlP0VEs04Xp/XogUIth/ZsoF05gJLCNfvFxQLsMfKOBVBfDgMF/G9bFTDENrlFz0gydNIv4EXiDXIXKPVQS4XCJSIzIX6nfDTTwLRDgGNl2EoODwNKTfkbtlQcQALUiOl/EC0/wGgcxOGZmAmdpuvGrywPkMvwbxaAYYmITyCfyKrBKhIFYRAHWvCenusQClEpIbkUG+NkJo+0+Bxrliq2ikK4QeOBf/V7SbwMEs4iQwxgy3IAJNPArww5kb2GVCKycwk9L2kd9DFQm0LjSjERnN6Tx6JDvFeI0KoA7Hl8mIVOb5tDECGYQ/s/Xpc2yD9wKvaVfB2LN604DCHKykaSSTHhaYaSBmBTO4Zlpq6vxIW8ceqw0YuWmf5i/C+uf0pyEk+08RoCkksd6/Y/4Nv4XhiTz0qzhy+pvcfEA5puBqODwN6WfE69lVMUATEs8YrkFK8xNcDp+pRSbXmQrlRCIMP3ZxgAlnw1Uf525nAez7/V6UweyMWYB+RKzxzoAZg9PJ8ESHQ6eeo9X/pjAEEKfFHHJ4FwAYXV+hPnQ2zxHimOwNuBroKNZ7PoRgjuFpeTDOUYr1ylqMZCFodpRL3yPK9dTFfI9AJxTfmaPKeDUxQWF/RBtk3v4WhQPZbkrgbG3xnSJ6W2O/U7avsdXWKLhZbHkjMl/S2bZwtx7QR+ADOdmDd7MLhgQT+BahAbx+QtgTeCph9obr21SAx0FwLR+eTICJa6gwgpcyilHKXO3+APw1f4fvkl081jjl5uAxeiTBShgPleYR2CofToZiJjZDhREXdkYsBewazAEJ1uHMTHqIoNCbR8xDMIOYyrQefY42Tanp+l2P54HsarBQNplE0AMEbmACZ6zTgAT4ZbwxYwbAiKw4DScSJBzUxMlGLxKdg0LPdmpLgd1uLczT5EuZQ0FbGZ7klErqB88FLeckpyjQPeEaw7fwPRky031fw/BI+w5ADM7d9IFG8uHAoLYhOwkVhrPhBDHxIiy4xpOUQK3mk7aXgnrBpqDqnZ9D/xL2eMM1aGj+BTWWj/gqI5MaToWe68suxRx8+3mUQgVYoBJfafXRJBO4C6aE1Xaks+slysQNe2XfmLtQht9sFdCAlpReXYRaGdrSkUtPmxirxwcUnbOEdBt0yFsMcxtKbGWRHUunpVYcwlbvXqJNc3lgbcEEcdtQbDk8DekmqCrLGwxQt1CpjJfnzA3Io+yUkUnup0I515ujbr3xjsjo63cnT9/hzueDT/8VkQXwqtiCCUHdzrKtAtQBovbSpvkK0gJz6GYEpEmGJ/JQesrRVjsp+tThJiHVOC+GvgQ2ei/MfAkpW7yAtuv3Gm14LLg3jbf/nQpwSlJxXeV6JcpeVxRR5LboUdtQhHBAt8azzkEccfYQXQOmebvbXIPYLnZjo0MWa5XtcoNdsBBLvl2xUzzuWMOcW9hhlaiyw+gLoCqIUmcLqVlQQcM10GmaYZNEpL1sZIIbWpqIdcS7oBF4zs9hDQohyzGRJMCGK0jAIT69S/PUCETNsAt3AYAG9xcAHTysM/WABobnO/ZDAJXW7mkR45QOX2n4cNqAnZoK5Yy5hRh8NydDpgWoDn6WhxTzOSBUEOwlzOsQaxkYT+ShZeQI7lV57MuP8MAAOb+V/avhxB9D+xWrFRBxlvQZPNN3xFGAKn74+3pAxf7OfFWWiJ1vROlMqfgs1pelWKbVpixbcl0TdZ+qA7TwREZMJ+SuwUkQLLSShraidAVeJKQuZy5RtXiSMt6cNNUwh0QyvJzIZHZriUpax1mmjUcBo+6Q5JWpc9bRJbjDpZlapFKVuD0N2GhzCRJ+YcoRkcR1Lc0U5P7k+8lTYCqecRiCB0YWexSgCrihXmw15RCrGJ7W66CQKw664vnHcRHMEBXOKKIyOBPeyDZlENlixBudSkPdOX8bnXu8Ng352edpumEmRgVeKF7r2uwMR1/BLEffld5VuMAjOCeDPhEnoOEaYmk+gRMmUPSyswROtUQhy+tPIyfDfjGmhnLVFLEzZ9NGF0q7V426j1V0QezWMv5jgblQGpvLNpt0IpKxIOYjqm1iS4G+ZuR8C6NbtIU2oCLYoqyNK0DFYjNlvDZgimBoRevgO6QFgEpr9mox28SplqhmyChQCQz63diTj4gVDoPOJscoUCFgMwyS00K6j+vdsp9P4gE8TvqcFHro6BYG+hgjjrhfnuun9kB50loLTrhYr3LzZ/QRtt38vMd8hPVMmbe+M7e9YxMvPwkgTq/S0bzothvy29Nr6fLNCrduZBm16LLcRht9iK0iv1FtPkQXKRuFjf5Y0+ROtuOaUkUq/KAhE3qIQgs5C40dAJcHxA27KOXdrBoyaI9dqaJz2JzyRW/OoTVLyWxEbpU6uxzDfsBWvV8saNFu5kZ52Ez1M6LJQxNWUxN1YFpq5svmBVNT5xNto/RY/e70MZ4FUheR7GfUcQ5PQ/oAG/O5DjBAObIxJuNrhzmLWsNOGZlqERXKGTtvnQ4/HbmqLEBnsKHxVbaXXZUz9R6PkZjMpOqOAb58aQsoh8SyEsXMHE0GoJYYnobfRso0R2NHx/CsfScmGtuVFsrCeg9K5f2qPF3o/lEpiHViNS2Y17k6G2NMG+/Gvo0d7AbFP01IOTPp7hOCmI6OtW6NSFQdm7IZlIl1Mmqqywt0UtY2N1zDOM1JVDkfyQO2YToBFXrNuvOu45d0QPld67r7f0ayHsNRW9xdq+mMizJeZXVW76fvfZ35NKQTsqbacA1cmnSUmkV2ZkQqRVqiGZdVLG5/HE1xQFG4GY5SMZ/201WTisKW6QxtBhUTxfnKOTMXvDanA5kiXNYbjmFOvAuMZ9y0rEjRSTbfpJTjvhenXvDzuENnT2Mvhj6uYoVinFNN2XJEiZiZ85SKACXJbGEZPwWTiLFUJot8J9MJVJq7N4k2TueiJTp5nFXnJdr/KAUXQxhNLSYGNqDjmMVhksWH05ASZBZG+NbFaWoUv5gJLDiE0RzHSJ8nAkakUYa+NmfizlXXMo8M/q1lNcCId1diYOtBRzHtQrJ1oYSOyrROxgetOYrhynGcC/FEpKFRF6FxLKiCWFVNM4b1VT8eKMVhxUQ/4NxcHJ6TZbwv2MMq/riv8XFaaJVSfXpf5IN8byOCaGfF4MPTkN7DpCUPbRmgWJmUy/jBhjmEwRw7ZWQajFGhnBGrQQ/vPJc1Wl5WKB4W6gp9vd0JwD9QTlhD6ZcO0R9e5pLsd7ouoNSp89SNnmVXvhdr0cog6xSIkQ4kuG6u9/dOE+8zgAHWIacojA0egYna6I1XR7kfsRluVOpm1TUs6MudYQu1cvZasWqV/moZZezjeJ5GsmcP7lRrWr1z0bu/xSjeKRgKvYVRPUZKsc3OFpboyMCdIDanhkrFmYyywkb3+Gn/DQDphsCOSGiPtZvUden7mKHJWjIesFq91p5fAECXK5aRBqTECLLFKkARMlyU8RZmlOhkCxOi9e94WqLGyMi9ZNRKLsJTrWh2UKtO86TAMMdrfFB8+J4joBokBCh1/8u6+3TdOW9+Z7hnPRhV4oySls7CIfcDuwV/3MlWNk+fqQ1p9tZfajFsSpiNWqtp4KBx2IS4g8Ix6ECjORHpgAxqlvGsmwOoS8H5TCJTnaJGT4zgL3PLXBptSO2LqCVvQSEdHYViYAsyKlL4KVR6Uxmgdqhp/6KfAeORmlBU4Z3wsNHG7uj6PgYX1LTdL5pufHH6KAbXKukngpxPKuMgOfoYBL4rA7RP+tBlfOkw+xDwrOBrEpl8nQrdKEX4G3yKQGf4EIenIe1FN5W9iwGSSfdYxnudCYYb2ClbdlqqZM6YT47jYbFFJJw5LLtYAdqDTuWdbSRwGvMd61ag1Lg5bqMd2rqtmgKHh79J5XYrYH0OOYnRxj0CI96wmnGdzWAzXKp4FkiawLfXSAMcnoYkQkvNqYMBCpQWLeNTjQlAKmSnjEwpiyqZM+Kfphi2Fc+ooKTZnEQKkBB11ieW2YlEZXhar30sR7c/jeOsFFs8RtY0YhfL05D8UTNzrGOA+FLjDNdgoPFDzOYztcgU46mSOeNNLprX/HlmQOS6COSLsuTDkvFFxEuYeq8AwSThWSM0CPM+9O62n27i21gOj3nD2vxVzKX4m5ddCfeV8oXV0SHEuWAofLTCao1PGcQHmtQNJQuauRv5DlBq6lzWNpLma2zPZ/ZVbQT6Rv6p5TBytGrGx1HMfOndOypTEbvM9VpaSGmH5JIGLMewS9fu0dAG6TRi51hXnG7eL36H89mEDINYyG67TlIPyEsyfhmvFuMFW2VF5Yn+kA42w8nSVclGoNDzlD5Mil/XunKhDKt0EpAnUoEX3XjCMl4lW8QWmGFHLmPOFskNlrCNieC3VWZjTCcNyAPJtjM1ILrEjWW8Nsx2aI6dMjJpjArl3I9NTx+5XHyjnbdiTCeeUeOlqooq2lZGvdUbNyiTzyzDxgzFMjxthAMFr9v9fbeLyHPjMNzgHOdMckFEvVMe6XJ0fDTAcHvLxTcf+2oc1KCzPnJGqPLWbp1VvVhNWwxlOs3gU/TvNAT+HzyNyuXy0M+U0JijlmgIDI/B0KDOI7TdtVdUzRHHFuya1l9S2Ms6/VKA3TgRfQwmhWmGU9SM7VvdOYjopCMqPNor3VA3mEtEZlyrYF1r1ENUh5wosEWPwFDAcqCnI2PErP1H1k+qH3VAtude15DKiJvrZbCRo5XQdkvaFaKzW7VrCDPEzKs2g8ivMLnJL8WQ3cJ4r+8PY2e4BU9juORCjUkOPz7y6o7eSk/4hA2l8pk+akg2UCsUxeE0JFIzVL+OSGZT0paFcm+MF8cQISobGZkEVJgpx+eDLWYdGH5gONgNg/AQKdODAFnHv8DvGi0wOFDOTh9FJnQMAdFcut9AUvXBA4IS2AdH/4BjclWn2uk4+1oI7FwjYAqRZDiBTIHiFGFEH52sFiNls2hC2pw0fC0sTgCsRVsvVgC6XGlQDi7vQshjsCIDoAABAADQgUQAUgDAAwDhYwCgns3qAvPfagwA85+4dIC89y0DQG9CJwGgswJpVhiAugTMDq8/n5SFAMCtPqyC2AECVXKHoSIDYHTXlNBegJdF6A8AZC7GerBbN9ZKJdmA52npHcdPkHz/IYb4I29brw3ZpE05gsFiCBhPuoog8hBBAWrRgi6K7R4M/MOjgkEh2n8WSwNgAx2fWD32ZNVBgHEM/hAFmch5XA2af/LMAjgIAFiQCzpgXjB/Za4xXzEnrpIA5vEb5QAAxmljivEX4xmj3Bj+y4tfsn85Pf3b9CzyFwgAUgAxvgYAyNuAhxG8VxO5rkpe/s/2Dxd1qbYWHEKEGz5X57INn2hS4opSnwbAzAIVIQACkS3YYAeVIxonbrZxtx0dAweXLx4/fLsECCQi1qBGY7BwLScR2kdOCaWlU0nPooaNXa06Hl4+fkEhUZiYNuscjAPUB4Vl5f7yt1WmUBESkiEbOOvJYKA5tki2yAgChc4nU1bIFriUMwzI8RSDYhdUwoGCBY8V1hAg4YDMHoUrZ1u5sMUDiycmNi+bvAn5E9gpiI/3iUnssZeIjIyCRjm1CmbVDIxUHBrUc2ri8tBxEWEtWrVr1qFIQhKUxhlfadXmS9chIBcWdgAAsgQAMHMAtAG4dwDsQwCrfQDM2wAAXIKz9stgA2AW2jIk6gPi/Ciwb/EFf9jIfk+AMTxaABI12YL83dE85ad8pR3wLRrFH4Eux6N7WUjMEyMuiAtK8Db4FEritZdGLwa+9fcDohCGfQrNDdzdDcLmYlKyQSchhfPYKbi5o1EKnEb34CPHkFBPReT0rDRkd+ATrCkMfZikGGpAD3gDUutpRF/n0CxKBKqABVzjlhtidv/gIYK9YNXc0RB67t5IGZREC+WCMigrr6gWFqZF4VD4ghs5dR5pGwtb7SJP5VSp9blyrvUlG7ia95bd4kaTW958EiGPXGyzu1sWNn/SuCDRsZjKZEGXG6VJ+prSJ5hKWriCJgBkJbdSMLDW9CaD8IRlubGBCJMCAcUixqgiuLAB98yzmILPvJIpqb5KY1i1G0vF8i1tsgjRpAWnhjPwnUp8U9z7Ui7K1szB4UHOQ4Dt5pazFcSDdTosbwivBLNsLtgAzq5Nc+gbInCbFUUqoBDCRdXiDFRfkTWyzWkALPlj2PeT/qZMzH3EKq00wxfxB/8Sq17TLK/HQTSxFDzEaJbBifEbuzZzEow0oc2EfcQrRCczgZo6JDZsJMFQCFkx7fEsU+pLi3MLz77zzInVAJXHkghHLQ+KB6aMDH4ean//60Q/pYsVy1dSMzoM4kSfpmcEAbTWTUzdkSEoQ00Cl/FTgb+RnaiSA+9YvwkPaOs36HM06uyFDBmp/bZqXMCSa5ZE5RQjSBN3QtOK1vYbQPQsHY+liYzXKpON4FW7aIEDpShjmLAWDnmnmNJQvBSgkpAig9LCELOIbi+BFkjwzEDKxySNdPIS45LTISpIH+R0NYnEd2064Hp1own8INSmO1faXdLLsNS7hiunva97CKy8cOyrasHx9JosjammszM46xUHbUnYXS0Gs9lVE31EKIRjFciQeagVKaO1aEaFR6Qnwxvpq7kNzqC97gGuBEJ5+IAQsgwNaJxFCYkHZuuUVZAAZqGvdIDL07XMh58yEpbTi3CG0oDdISzZTR13ycQRNt2lzkjHITsPI25RuwuHHHenqAw7BTVo5YRDboV4SKcDptbdUkINF6xXE5IMGKiJVukUYdVEC05YwA2mokRYP738EwR/pcEEisUJVk2GKDc9OaLwASj2ykDUW2/foTRQHpGjCEjyfzWjqwhL7t5lojfbqWaJEHERJPEVFqtG5RYKEBkCSQvqtPwkXepAAOEL0pp375SGTs/6PJ36T/46N8c5A4+H20ghpZtmSw9ppkngiw33z7YpiVrRTg2yk1hZBOrNgwM4i7DX+AwwKU3ZT57rkpN178EkMhFsMAKIcorxCEKoK88WPCFNJ9mVFSYJOTbMN6FzfL+kbX/G4YhFQOiIEmAxx0EjABOUE6EF9ftD6G6asOPKA0lmBBgUG2qWhrJdlSp4TRaeo9M6W2KVj6EzjMysQDE0pS6V5CFm7gVtYSX3ShYKBpfCS44EWr/s5A8w1RNDz7mjv0BJHDiNhgZ4EUJ12LdJCgwPDQP6zgEQHnFYLxoDBQYcUSpYGBUGk6IYybPdrTEo9WhQyiZQQ/VMVzMGAnl+xy+Zcxi/pPrk6Sqn+pWXl4hkjZNx+qWxigK1oJqI+w0OyMbJqWf11ZI49Y3QXjDYfxEaylH4KO3BEPZ7NbDrJXUDojrCTQDJWJE3LFFTmoBQ//QCwwXthcRCUloSEM4/nCdrbudJVIRSFppYpRNASG2zWNHdY74DG30hXMVUA/IF39PjVrvkjH2LhtC7FfoQoXMCjLLamW+R1l/N2RLsNlaW3blJ4FT/eKI1QXfc6/8sa3rhCqdCXHVrDVLApdolgMSYG2M0b5AE1bOuAnSMqXGlQKJ1lM7RaatKSVsLgeMxmARhoAedriJhb0QOk5ec0mw3EexAschSXn4wS0qK41OVgpglnAJAJ+I3bmg/Ol7h8oVdcqoags7g2P/gHBi4cryjucBn+CcmcDVzGJiZQFX8hq8qSOBIzDfM6FIHdCeztAPGdeIge6CIx7A37kfi9hOvbCoCSngeZBt3o2u1ewRt+bjG6td5SnNr+w0dP9wsICRIrJwYO4CO8zXLJ4ufxZg+sJY75a7h5kCJwaonSAtcTyM5DQQltORmu3JMNT+i276ljGr4GT81MeTZXsbfznSHWG0fHgUlbZyt78NmLUUe9YhdSEqO3fwQC2ySGfKOaZ/LpwoIGrkVAgSAjM45N4NZsi6HlnWJgKiBNvAc9V1yTMhVBfGh0iTZXBwz1IpYmhwM64NZVUgArO9wF6EFBeJSpCCd0+PU4Qg9IPII436BsZFH26BsmruARVm9VJSwTLPtSL9X8v7izPeFStxGk5TM25WQ+w5Txd220w26yEQbekxotN1eYJiA7Vmvjf5qtZPCbK9zlPVyFphOLb17hKVGwpOslFnLZINY0I22Vq/jfIKzMGyHvL8bCdCHmtblqKhpmpr88hW0odb7aiuN08F3YF41+YF20AKTInl5XksMgVHUq6ANeXAXZPHECttIWxBgL2uU37KB0iNoG+0Z5Jw9WKrlPobtngSy8oNEYNNrgh5uDw67/GwjBNDNjl3lbrVbA78E6dFVb7RxZlWsmY64e1Mb4D7tZlo5slHoEaG5cjHYm4voKfkx6MB5g++AOqHobSAmVvaV1sllkrChxfmCNaIJ+rlKOGni2pMQtjkj+a5tkggzTNJ7WNpMBoxlgV5a3eH3XN8+O2hDZO/f2hDlL1WRLdAUYBEuDsaWMdUijEH8xB5ED5bIK+Bpu9yZqzLCopTHkWto5yhrw3ksg7/mryYw9aF6skgu/GqeVHrYQXVXK83tNTU/NMshGxJLcNDcfzQ7Sdi8D0m999GtrCiZrsV57ksECZ5NPxvhOaxdRiTgZ2OaDexbfhQ/HkNy3evkhwXSmvMYTjg/TCB8hiPivsmnhO3zT1hvbjYDROdM7XLed+1Dgv+eY8GpC4DsrVPMRBdoHO0GQasBMJCyypuvNJKesrK0PdEuBaf3G7wnbdLXCfuERFYiETv18H/TdmnoHDtR9X/bGTtFIESTQd2lOTNpDODMqJvN+QEr0ZTTksUtuu47vz7V1EjTusd/mB7ByPmCZuomF73fEkMf1JsJE306pP0A+Y2YUr8x53/jNEIDfxrc5zXEbDE5ucxUzCtskwJMLUFrSwgRuFNtzn1EjQEukAL7J7w7J13xkQvnHLRCdZwv2WWEeqqa+8XqSZZfNQjrlL3Y8TMcuJ3j/HL7cfT040wH7sDYCSJ7oHXcNgm3Ner+6KHvG63qWU3nhhND3s1BDd+XMrTMalo9ERd/RcEOlxlvpMY3lOG8LRYCcOQ61/0JK2IQ910ZAfzEKYF1t6gHrSahhh11XaU/VMd/WI23uZpl3o2C2nKOsq5BqU7qtdc+k+ETvwhXHRfTzi+dLL3/Q3viD+oofeB45i7HGEZoH07n5a4NpvP0qT6FL+tBXipHKRvyqShD4DJ61Rjy9ADp9iYGOcpKtDIm+bL53VMeA0CNTQJ7xCtwGcP2iPcPI8E1BHbtyZOn5TGMKeWn2BJgLH/6CV/ZbBdHXn47m7xOi2w8U4ijNByYa57VwKCpllFDpzoToqQVxq45VM7PCg0l60LSBC/medKVtKJIF7CnaFJmXsUy1IC78PEXwEKtIwHoGEtF1u6nJ1lRQPtwpUtYpreUzr55SJWwWAAKKdx8nHdnk1xZWPRexJH5OCOKZpU1JlSSgRRCGBtB6wtwGS9B9DOJp+36Sc0NZihDWDIXdMVGQVljmTpLcsBPsJcjgmV9POXIr4ghwtUrjqGIhcfCPTQUjnFXZnhQ8u2M9OWnHKANlkjtRI31CPz+43O2T62V5V0exeDhc/8ttnkkbyWRdUGpEvgqXqOsylyAfmgQ5p5ld2yT5pXDowGvQI1X4Un2c79exl/pposVDtIi4xoS7p+5+XpF0x98MxYrtoPechaYHGN5zGlxbbIDsduk2skxEl7ES69BAwaMmDopF7SF1aZjlljFGO3QYlgknjhPiXVLii6NYyoQ9A2loAxLFq1DsCmlS4cxwNAHjzbPDb6I1AAlNhdU6on2O8xJGJzGmTS+1Wt2l+6V3J179zxwtQKt1Szg4WF1r1abhTiAsjP1TIZ//y2H2ZrpnxIh+AViCpzktT1kv0PcOTRWO0o2XqYcpIWsr7LwQs5R7fxRqklAnGrsvt0sLn5MPdmAWs91hCbuz/J1HDp4zDtTb/HfRxYB4X9e5J93iwOSrZyMVa/06LDRqIjcWhtMGysI2dpqSEfG0bETLJuoPj2/2zJqV4T2rVt/5c57Muc3E58FzcrFqXXtD3JUk9ufcoktMNXwNe1qIX3nvb9z7upypulQ5aOlIj6uSdLLsVDy3MiP/SGbe0AacQuGjUaDu29Q11jkM+FyHC04fmxEhZ8E/tRZ+LLFJ273n1T5xEyZKUUclxgyZgSB8JOvSA9SsDUJPbwgBeOHL9793/bb/578d61csnn7/+myBGZ/9ng4+0ui78/mv/87rvf9J7AenDkzf/C7hvnao/3x9qznu+f+9ug3iJvszZmgrcDqYKCd+TJlQ5OFSVGpC5hzJapCRiVfzHd4WeWtzT7uDxB0l+tzN7H6abQ+VhOgE5RJMM8pEyG8ei+sVHlgfj2SgN0Q1AaJoXYI8kAJKd/lgcH5n2Qa3LtL17Sxc62ywrfersrOU8HCS0XRwR78OFoxMx0e5ArdypUKoSfIU9ujtZx/dq2E/wmoBSnouzjLx2jmVxrrzFRI+BouiPtYGAL6mXezKt5mxuh01kFHqWZIvTH415SM7/SIxYyTzpLioZz0rBTYwrv+rQgf29w7wNJFJ3TrvXHuDTb7OnfbqVjBHJ9uHdDMxAssQ+ShI45TG0a2SUxS0DwT93BigDc5qvz2yHRW1vRO5NvRmbabrHlt1m1EX6DLGm2yKlI8+JhVR8BNEDaz95yWPt+MsTFs0f28vK/NmleFMTHdgEJQamCOUyaScZweWKlymylSMXCPKQRxIBHMhiA2LIKUoDkrL9VLwz6TnR96gBu6rwsPmLLihVDzLGVNZXlmGY2Wf/3R1fP1ToETb20LbvvoRDDNOH/VletzfR51xU1F9URifVF3uwLamZ8PBLnCJjlS6g5wy9txm9rh2xD8I9wOdDPxLYPKRhanVupc1+odPJ3awTnOYB7jdIBHb4QmauYewoUmsvkNUgHCdzazlf54XTKBjNfAX3f2ZyfYCwngIRZrCBZAAv0r27cH/GyhU4aioY+3Q5sTxJrc7X72ixD8EtsPqISKNKagdlncV8Licd4sIf2v05BqWlsbqRJx7R6m0r8hCOxxSivEdBST+/3mNPNae6tBJKwLQOCO5vXYP7HXPYBCCGhj7kUJAhzEYpbDKQmi+0wMfHZ7ujf0We/yCBFvaeWp4Ezi+WlwSD0dpDwkE4irVzElK4QPk7kP6ZKqVckr6SuKH76vmx5mB7BQTtoIEnI3Zfkf3M5vfHO85NCtil+CdvxTEXur6FXnE22J5klFRiz+tyLxCbzo+/Gzj65sfrd1//j2u9c2C368EIB/EBEd+XfxsRMdpLvMGLhLMB2t0VQFLI2b6IWl1CKDbv1C7Vl7vTvWZG7rdK4RlNWoiA62jE1BHiF/ll+gAacIe8IrZRyxRY3ytMRDmelv4JsVmmoJGXc0Zz69YiErRGdQPvZxEH8lPfNiZrO0Ui8l4/ro8+kP0JXWjCv4IDfjcjYn8+LkHyd0OW9mpl/BA1uKPEKDvJLlWz8Tf2xOwbZXkEqN3NAYce12NkYSAYYFHoYtDLoVGoasgDa4AL9iGOGP0rvBn2zPKw4zWGPQCLSHxQgXx5PtmWbw3k+yCtMAYcAjWp4LpXMuYpb7J0UVH3HudjVGDHydPHtOb018Zr0vq3NagIFCwxDKWFy3gIJRn+CXNSsQqMHBKSNwKrel4LARQdr94npPkcKxRbZfVO8pFJvZ5fBmqbosGBaqfVwZwid9EibNGo9PJUEJQZnI5jmlw1KetuoKT+TW0mgoEKznFpcGNixV5hhXy/H8Wg4nzl/7dRL4TrsnsseA1psqD4cP4M6lVV2NXF0H9tzwHi1+lFyU5HE9hejUiLEh4go4J9kItnkqM9mbRzaEnM7VYgYKOZlv4sJOmGuD/lc8kZzEyJLrKhRVzoDdF69lsek0FWwFmugbyOORnIlTUVD1XGwXy8QcuRGzJTedwTxAPxPfbBn4ZPPxlFbXbQM3LbeALkBPoerZzz8doRbic/H/iwCY5VGvTaIFFpUwVGX63DdpXAokrJAeDR/ITKSlbsk6YDuQFU9LC2UdAG+S1/voRyh4pcag1gzJeFYG8Co2yXhakJVsaYjtZjHb2ENwO7jYHfCNxvHVZqnKsGOkUxA+wRpmnYC/NghuEEKURsV8pdIg096Kj3AF7n0f+0vgrqc0YyRKXVlBsGdOEy5Newu/bPR+RsYV/Hz86NTvJypDQ/OcanBqexrnbklJXRXEU5xBmtaq8FtCffLL9V/uOqj0UDVJpW+5cdp9BtERLrMhUi3X1RJn5n/lqI6Qm8gFdeR2X05lzfA3JF2NO+Qq7Mth+xjMcrYVpOLF7xXAypx4+j1yCe1qTnb3MSTFQbIcUGubjW5ybahqjjyPdDqPTAnjszJMyhSXTa2iQh+0+kH5Ymmgy82Wq7w0gVEIlVQYCoXL36ihsox8kaDOC6kEAYh9DmJ9wKa5ShheGmsvxDwFLQZJlVaLdsXuyO7xxPjVyNUVMDQWARSC70zMbY6b2DwGHWWb4mZ3Zwxc7yZ1e7VblgtC/sv1dV3PkYDXQPJS9aXzFTRyikIC6V0sfWmKkpW2UOnD0DeZSD30amGK3Iu0UH6QWQ3y72U+m/KJenDDRR7vRsA0uOXZlD7XrXVjG2+gvBsbnWPgixuaDy9Yb0rAtS+XCOXLJdn1uP6FPwNlBK9MDZ+IEJXUMPC+y52zmfI2LvWNbLlbUsLkShlFb++fyz1RUPAaVEOrWdO4etVkKrEuYzF1y7hFeo+vELNEkELE5ytEkIilEA9lLE+XZizNcFmaIU1fDnwIqkQ27+wjupYCFeqJdFYG4M9YAtZn8DIe+iBbgcdDnz+92MAYfu1h35b+x9eNBveGQWXnzVvLvrpiaB2D/QonDhSCpgAXVbghrkOKyBMV6J5RVgTkE1RJEN8hSTAHYbiDwWe2w9WRQ6PpgUcjF18pDMYjLr6E7/BBYPCiYhK3a3PJBPni8fgxwCG4zzbNM+exUTpsZqpYRpgwPbV+7o7PIqSkq9mf0lBYZAUNQZeqcX3LXUrl6aWl4XI4N/LV6dSRTwwGEZJTLDRx6Y2IqtQXFKh9XETJFxLF5VJC/l0ZjFsnLPjjn9/K/rcRUAhoMoNfUyord6CEFhZjU36RnkZzFeXtpYdZulxFnaQ24Q/64XepeQck7RwkR2kV8dimJrpC0UDnmHhihQXJ6eCK9+dR3wOtlKcKzGcJLfWGBOUVodLSkBoiRh+cTp3fUb3KZefnDBit1PSvWm+xudCwo1kD9lc6TrSX+lOJJkKOm2gEUoNOoTJoZSRquS+mu1IBMg0qk0ZmJGJEIpJLVBDwMqNuquJfY8RHkGhVZTKTFugi0+rINBBFDKgPJFalvZSW/hlOl1wuFfBVfCZx+tv9BYsOq1d6pYRRaewyqjzxphnleea69v46WsjnUcFRKpXLgnLPhGPvrl2Sk7XxE+bBqRW1Vdr/X0XIHltdKQPbylA+Xbvmmwzcp2vXfpqGF8k5Y8Kvhe7K1WwJl8ZQCYe24cT7ECgeFEru59iJYPfVSs6hHg6gnC+mkcjU4mIqmUQr2hG5CAoGeOx0W1wB6V5+/n9Mpa2xeyTwHSEdyZRlJqW7PXgPfFAdq9qYAA+/c/QMDw37oqV3cozZ2cYcPAHBYwIBfHtjx1pnrTd36O2EpsSMEtIJDXiRmwjgjQnkvUrWZAl1Atrdtk0dgIX1sjKWvYb9tE1xAx/mIBg70J4sD0CldeJSZo0NetrWkvyennWohHK4Kn6TntCExzcQhPjXS/mdr1Lx11cceDXKLh6e/eDBK8e1fac6ZGlknzStQ/zVw33GBa+6oK1oxqu/Z8kefhmcPiKS1nwKS1379+CTMUPNqG8NFVTPr/Ye+gUqCJPVZhfxzUZzNGfSfsCbNymPA7TFm89tNoPdaWtvnuklDVSv8CqC+zaYPbOn4Pi5nZNOzb6tYVf6hifM5dSQYhKhBs3oEyCzI/GqCaUGkUkFNWQqf3VDQ/qWsGafc3Ln8XPgQTrPSKHoyCl72D5aB9ZB8xWk7POiaI1FPAUG5fesSRkXa1XKBQolKkwZB70nFAO6cAzKG12RMr5bhypYSiW4Qqk9+RCm4BmLKFpSyj7vTmoH1kHtLEzZw6LojBQeeCHtDA4bf3ccA4Np2yK4M+CCXZYsBjQW9AVWZFn1doTFkS8jAL5ayTnYw2kCAVA8AmJow2Me4quMbPYl72fvPXfvkefvPP/gg307WFjQfW/y3tCLtxOY4I2CF+8NpXufv/vyfdjm/cLdV+4XHm0MJD6xpPWjRN/i1r1bDdaTkT+t7dq3+FPg2sWuxh4lDSxbm76J1QMQXjOxF2JgPGPXl+SvyDtPXM87udLOADE7AbCKIfCD2r0tts0fRzKLnbqRZ15tjVlyrVAqM2KxeZ2xjlXevLrA6Bfka/G47bDjQxb0a8Pj13MXA+7cidvPx56fvL1L1XNVfLVEA2hSeS7rnJunEsjPYCVlnduICzRlnu612NKV9ORs17jmwuc8JkouQkoU/tIskIVvntrrlyAizO/ko/GHsc78CKEjIgB5HJ2xfaA97wyIC53Zia19dy32VExRtF18+pmON0D71mVUfiZx5l1ilNjlNXc8YXvNJ+a/J1SBs3j7FHGgc+anPxWPONj2+pW4MWkt818vO2Hyu6TVO+Zks9G688nkR5XQ8WF91NG2reogLJjNtNustmG0lcMYGYOkjCJCYTGxqIhYXEgoLCyiH0AuyA3Sb925u3QB7sjuKmzc2HP/lKDxsXjjYzXYUUPP76dkzt3gINcw4LUekIduWjPlIad1rJF8o2Y9qJRbCbDnKxiI/JQ+BCv+xt7/9dQHGNv5W7LdmUaARjMqsotLrbMvnl28xrH/ZIeTSPKRYDv28LR6KCfxGC5i80lMjyqYQoz12OECWWDHr0/VYMQBXvDw4fWF4hsaLDUnrlZz12M5bH762YUblKajO+W4rpi/eizzzY5fYFZ1Gc9AKdGRU/axfTRbzEbzFqTsMSVlx5izT7rmHQ5VcFMO/Vp7fM5PF5qQ/pSGVuxfWNi+zzUOodOYflc1NO/nydg0lL7J7gncyblVW3sWjyfcdNSeJXw1l0R36vBDZeo0Im5oY+v1MbbYJRcz62vYb1pbkt8RlUnZEEvJkUgVbGZpCvF+izlRWnv/FUJjNr6JkH5ee9GNBHCPdOb1g/0pK7nA229OhfB1hzeZvd/7e/7rkH4+ayVgg/rLP5VXD5IZwC+sMjtzyVC2HHaTOdev+m/3q8/1L0AvPLJR5ngMK1NHGCIGq+cK73vg9Yx/d00xe3BstYx4KvZC7Pk/p+eaVD/V6RFpMU98svvo8fmXfj4pqBp7es6DMoaDCy3nsKuym7nXnJp9W8IN6RueNKO0kOKajBo0oU9G7YcJbVpyKVoQ/fiXU59gop4/RwZFg2As03IIZFYf+vUULQenmg7/6Sj41kLNueuTPMmeH793pY04gL70xptPRa9c+r0GtFyKxqOsy+WLqZjsmYWq2H71APYYhyPYgoQ1dhJkFkd4EbDqgkgsyu25BnLu7qRbzLWO7GxH0GSSyQyGb/5wx/82945ZhlgsQS6m7J+3DVKppj6evWK++SbKPFfjIfqImHtNRCTqbuUSZ3VgyYjetaA1FZjjpMuPXFtz1WxCJl/QtqBf2mdfEEgBxnh+SHlu4dNlYom2Ohf0/fnxZXLJdPU7V5ZZ6jzqORcQEVQpHGGjLBUxIFZCsyZs+BkTqvRCwrpkaX7OBIv9AZQ6bhi34m0mFXqRDU3kJJIlkvpmCFQ8Ek8nphd1ZgvcZD7P7GWqFG4m35bVldbPYEaLMq2zDyMYlCLp9PuZ2If53rAXCK0dRscX42YoWuCHsw4vDk08F3tuYuMmBlzP1Fd19bE9en13d2/vjmhiPV1VVd094PiqyPbItQv0Rjy+kZDxXE3EDRgGMqMtEVQNYxPYc7/49YIK7pnAt5gb0ItPAxs6DIB9dU9OPofRRerCTJ6oA0xzhKiyXFpkV70/Q11NXlPuryzTqWXxW8Eq9tpyMNYzUIVd+AMQw5mBdacG2uyzbcfT099pq5sF4c/NxK3wfEiQClvjVndrtJH2937pgqTPrwNyC8DM+dnWJjTMlUSiIqnIhSSSqh2CGLGWz5cKqIRAyv9aKa5WiaVAF1f5CDSRJkvfXClZ5/FS/HlgQSZZsqhu6IX9vtzf6L8mv7i/+rRiURY3dSHgEOIHvsxetEQi2kTTuVl/rAL5s7YeharHZrAhPXGFVR8tLQuiz9Sb8d8XHmGK5QZtVCs3iJmHi67ilyNEqieCkJmmWm+9wdHgrlHWz2Uz//QLF2fk5mYUR6lp4DuC7Xij1YHITNPnFuhVhSy62lQsKLVSGXpuDAfJ0nFMYhpuk2PTWxxvp/9cy744TaqosHqyczKHXlfB2Y7CM2DtuR9MXodGr/XWmhq26rY2bAWuNWInia/o6lpXT8KzvMTs/31qX61bbosSClB0dsHbX11l6CI2D96B6RYqzsmXkNxpv2zPGGx2rdGvrLGUCcrLf1ow+oArgSo7aoPznQ8nEkRiZP7tyf4QMU92DfikaaJCcQAdQ8WBqFCjjaxAZEvM0hoa08Qf4zONNfTSUkIz44kmJkFiFKpknHbO5BMKliLa9As43PX09vTr9s18IV3LUcpIvvtWj4jGy6Xj/TVl38q4NXXreDIBkynj8hibzjLSTqWmnkpjgJYI1SVcIIyndntNeLduU3Z2py7bXe0tm1oNK9cgP8hwRl6Gqfpb2UpD3uqXgM99pLpSKqUgIq+aEexQLiD9n1xwKZ/0WgH5dXBpZG6aYsqg304bqbZcvJ+b2BinT5sAq4ptPTrVsA2nIo9XYZk1ToGnBiOrHgjcU6FHbsIP/HNVvOFMj724CzF94Nw+jV92sjZcniwjjcj0i97EqzJ1+oN22uuWr2gO0sK3Audbax/PyjjYCeNH0NlrqsimZaScwsw5JRNMuZOW1dhnQ/M95WF0Z4pH5Q+E6iKBcCSTgbZ4t+zriAG/EUn4d8R2uAEiydPF7+i7ASMaevz6nOxd028HL0CSHuucyj5+ndiIfgxoj1+QNiUK7Tzz2qN8rypzIjbhLpmjCOB3mjTzNpFvkbiqKaGqHxm9r5D27mQKd/+KFr0/iU32Ev4RdSrUn8XxKnbulBL+hh3Yjl5UfqzHQuy0JdoANH+Jnca+qT4E9hVIdiDGXY2KourtALRGem9CwYU+58LIufOCLewLHrhZvja3iRJ/8UpbZj+P0rOjuPDer8PTJ8//cRnd2xyN1IM3Nv2p9N2byzRbHu2DCGCdu8QwCfslYJes9pnzLLGOILTk5hdZX9zMDQdlLDpPtSkwYAzM0/0r+Oi/6GHNoc/bwAxgpESVF3jPDodguFokLijdcwUmBSiYQJk0Y30kAjJ6Nm+ndb/7/oJxhiVqIgDMsUKkDQ4AsAwvcza74C+s82Wdddhf8L0zsMfkJ5IfNciLHsUy7Cf6GmhozTLsG6ZkCHyDiXb/zpOTe3STYx8o945z92bsY2MPBWubnp5kK/apsYeKdWj2DHnTjg9lyCy5shO3L2ddnrwN3liRdwpy4C87T1wfzVmj9JKtYNz8S21nt5AmlxJsbnid3RZzXe1yTbW6rrRivp2v878uHLVEa3RMtL0LnpztBSv1sCSAFZmrw8Ttr7O+nrz9eoRBFaCoIiDGvhchF/gek+zJJ/vRGIyElTEFb88HRBl5kBHsAETsK0BespxdGNd3J95/je7FJ2Pydl72W/kbwgHLG2WfNG+QbhSMomSD+e/dL/3LyvYjeblnjzx+ff7tWFKsNvZKzN5doDCb2Suyi4XW2Rev/T1DB65JdBA55sXf41lLPxQh6tKxt09CWnz2RTD92qPrn2XWjMH0r0SZL34GIiya/D8iX0lz55U76IexfvWtdFmtqk+omuLIxuHi3b/uZu7srSoFbiOSQOBUIiOfkhPnLWHctuun3a4jR1zFo78XKZsSgpUupTOhbNq+63cfD/Qf189pB9cn1oPfR/p63Gu2c37krHyA+/azt3VLH4wzjWsd5gfaJ9JnWxBIMcXzQ+Rz30WttbcYzRGDA08T70MWmH51VCN9EU9pgOqoK7OgP3jg5/BUpo+ShxdC8x/r6YeZ9mxmi1F+uuy4d0SmL8jqV492fFabvA3HoInbzDfuZHFinmdWzAWzntq3wRsWdXjW8SzYnla7jYpxyXWly3W17exm0tFlhJFjpLM7ao5iy5vTcv4SoMTPCpt5clZPAL2RDPBfBmfLutgOgT/4Ulu3ERPqiZTu6zZqlkibJ2ZjTkATykLmvTIyJHlkyeIV7krZsrs0ZPvJRaQvC0aNhWw3a4m1y4Hbt3fzzt8btpx3oZ22n7+49WRGOu1Q0f7i4rWZUgQqc01dzNTtzkjnlIAlwxDwpBazRFOwo3RI6sRStuRTvAG59O6LD6J/bXjlJyn9O/CytqoclOyr9Zo10+vvl/rXZYf9Oiu5kETcSJl4Jg/khErVxL1Mqn7fhl1cqNbqdMsMnJ9i4rE590zSvFKOdPA6mB3o1UqiaH+Z93cp9ZWfK1TFgBMdvAn2DmPNrW/RIv0/prq55S7jkbl8R+RiS/GJST3Xpc5bskNLmYRjMnEeI0OrKbc6a5oXg+U/Mr6KMtTPZHFj/+/llpW0/RozPg0Kv9zjuSZ8/YlM+fHr2qsP+H/9cD/yw6+xF9PL8Z27qVC+aBCs6n60aBMFx7TsNELz+q6c9tCzD/7Ycc++NkR6PoOXXPOAOe5Rvx4m2l7g0BJg21N+qH/zw0uAiKt8eKo2z9UN3CQpl9wd+25ZfN70t9o8122Y7fZ2WfefQj0hcXR8zM2ifvD930gDQgt1/s64/4Yj8BoK+XqP6tTmJE45CVbdy1nje7vGNPrLJDRV929fvBHHCZ6bDYI/OKYez2eMlp9P47ShcXaUar1q4kw8tX206sqlKFMacSPhJQe0d2UHnnr5t8vaUQ/sy7+09vL+9b8XAy9F6X+K1bYUqL44frVvQHY405rynpbWREwh65l4JhOPRZdMTXSmnLnui2sS5fxp7Dx8xphlBdKbdT7W65VpBcnRyB4g8vA+07F1iPtFGqQ1uufAZZDPcVHsuxqlKuPPdRti+Xe28JZGpDRPL5pH5xDFYaifidv3wiH1o0vvM56/d99F/kb5f8PFoG/Ln23YbOu11tNpqWe6sWvLf2m82GwGUZDYTtRy7oZcgnMTJqB8SJ5qyL5/isxRApoeGxn2j4D7et/IYGQEJPUPjcQOAusq0L0EQIkRojION1NCIcXlmE9mLs90IXu9fXCyO6dhb8OKpYDsoiUyN1OrvZb9S846vxtB16jT6gR/9Gd+uGT1Nr3GR7GRiTwtoBjJU8TczjA388FX6iiEB1oAGgEZDvaxx80cOgjBgKTa/lQy2moS5WwLcT8XbbdIecBQfn8r5KjHZU/Pax5Hz0oc+KytYecL4AVhNri4vtoATp6sbQj/XLL95Nn9nPb7zGLKNuXjYb9ar+1Bvtv3Bw0AAQA4Ice9nFUu8ANqdXZGeZD82ClHoA+o1I6z669T/xtPTzrRqel9mhEjgwwyyCCffPLJbwI8RLgleRYlWzFBib92ijbfR1AluSsZmDAT+6dq01CgJP5KThd/ULwjcXVZeRzq2qmwjnWsO+s+yPsdijHEEEPd5iXe22a7kmWGkgBSQQ659B8OAO2NaIKmPfAJBXZmec8SPzwF1mXa33aSAg31fjwIFf1VRUl9uTclG4DqrrOKoxUu7BuwhFBdFQXWA6vSoVfME1S5LDdsqlm4tJp0f+kG5nXLCm4NLyxtTk4r0+C6+RDoNrd8zGomWSc8WU231KqtPqK1UWDJiqufdiE/DV+ss2nqxaOCin+HhQmYVnpjVOPEiffGy50WOVJthXo45ZV7Tlo6DV+h80rs5XaJAqxTeZdIUf4y+nePHbRfnr0H5hbdG8jrjsPgPnJ4PbsBi3kN7MDR+F3p9wJCpQIXS4wdZHn9tcVSY9ncPMW9LVuqJQHzAGkYr3/vUf0HoF7NsYpjVe65npoAmUgmkclkCvk+mUqeILXkWTKH/IDMI/PBucs6eGZ5Oe6yNqJfe89q3h8AgN3ElwD3fvQdKBsiAcACpOtHMPcyYPF+mACAJ0Dvw9w6zXW3di64e4iWhrQSQUggZnBkRe9dSGEpMMb0kGrrDK3Iuov0PVEngB5TEmF9Nhh75KLUTqXbEUIlClPQS+GBCgA95CDAqlmtqKop9DPgm1xrx99WyUVhtSMcnFoqeilcwWoKEwAhcZgFWarnAoeWi5ZHWa+w6x9QEjLyTHqqmlOFXPZTRvTIreFinutDx5vfuijXVZeaH1nWJYav/7SCPwndSju0yn6qxiZXBsYKDjF7uoJQ/ua9xG/YKQHf6C1xdR3WUdNaILrVCotTu7nO3Gv5W3JreiRaSrxrVk2eL/87BtXD9hj09V+WcnPDSF/PUvBq9lM9j5tYaV4DSgBt3sqSmqvnUPmp+WhU7st04JtiS1x5QGCMdui/eHiFlBZWeVpNWmt+Sf8uUoZeQagU6HenQFP5WNVuDwNCF8n8UWu1H1SnK+kuH2rCHSGXfsjWGGxstUOV1mMjv/tdmnocpNpvMSB0kcwfa1vLujp9IaI9VvIeICn9tfp70fuxrDcCwuGRZA2PwcwDAP9+aBnGxo+RlT8llu12KPY8Ag4UAAAE+NvjJvqooWb7qb2DF03k2knClieTxxK0AaWCReNZ0TvqvcoG8GhohjdR1NPE91pGK5QujxI0ER6ekHFzp0TEREXu2f58KBCOF3o+YHnXVSCoiMQVYfbm0S0b26Q6DT/Ygzj2cWDaRzsi4w0V5kgWSq7zFXLeDrt9by8CkbiscIlyPxd1RsKRYar4ns/YGSbQeqzNl7jjUpegE8AywSJwjVMeAe5yPpTwJuCSPkhdKPzERXdkKOGcLKhZGF9NSaOaY+deb5QqkxlPxNJQf+m1HOAnj+KmVhKiOdvfHnIPiV0X6BbKcIYK6dXXJn1V32G+QLQpaFW63SemiQyIcfZV0bNzH+OrFJldMKMtG8TpxVfzYBsMaxEgK0D5foRNELbswwkluynhH8SfVz1GkbogilwORkt1YsIDH0SIgy92oQpp9iK+fiKb+up2NNvYpcIzrlsD5Lluls9t3JYc5wdtusCKi756Of96cvk5q7fxgfuyRNPRlsT+mTiKzr+v6x4s5bQZ72H5kmqoOS+9lOn8X75Uc7FuJqWNE3Rjz8vu2DPfR0tatY0JeV7a2hf7ZV9GM4NFw6dCW1sF70mZmvl/iIwYA5AGwCSAJgADAJIBaAWgy/7Mqg0yESJHeQsfJ7LunCUebHFlPgrI96ZsS9ZbdIL8J2TJRXi64d41PocBBYBEFQxIIABAb2ilH8HNRj8KnpV+DAF6V7CwYv1WuMjtx8EUbbbejFFH+mS0ewiuXULstED8W2QgAqDSIsQlrFyMS5BPIws3n2ZesZzvDW+FEfCzU5ZF96x1D/qOgqE5xSeI5oSoZnQRlDTU3GJkolx8wjBaLcJaUIVoEdTEzC0K49uLEgjwsuS/ZxP0EvYnE5K80u59dNJ7YUdeut9eQrC8VafoLcBODPNzkE49gO40JhiMFN1v9nNrjIb3arsl6duIdeVm36rhRD4z2KbhBB+/V3qid8iXvkS16HNMHVgSVq2wXtyCyBIApidB4ZFjnnDck8p4YYlX4DdsCd731Ld24PDB9cx3hn2/bsA596fBMuK5RFdd9E+ddnpBuKLASGN+lORjQcR7LSV+t4ecMDAxv7CQQ96g1ELlB2Fabw818mf9bTU+kaVdB5edpg12HYJrsso61TptsNF6h+V5xtvuUjMx2+RdVgndPnRuxYLm23q8t2KC12E9BG4tgX9duHKLFYJDrKHXqjXr7NmxjbsvYWnC0OiB82zAQREcPEKALZCI4yQisyJE6HJDiLMe6nbTLbdd16bPPVYQtQUhITbPgLEOiUyh0ugMJgtkc7g8PgQjKIYLhCKxRCqTK5QqtUar0xuMJrPFarM7ODohJYOQU4RxqaDpvWqB18fGgrLtnvtuBEQ5dnHRTKqK8D5tnlIaMmjEsM36QqvsMPNhValmYGRiZmFVw8aulkOdek4uDRo1cfNo5uXj3wnYHC3783TsSOyrscFG8d2J/dmDwxOIJDKFSqMzmCw2h8vjC4QisQRIZXKFUqXWaHVthfCJT90wbcbn6Q1Gkxm2WG12h9Pl9nh9ftcMe+2lt/WEqD6eOeO/n9fLzTRqtjsD2a15M3K2jU5mN7lVZ/XbI2eLhG6v//4f3PIgcK5Y7PUdCA/zEBT+hZq1fB4FVurYgG6TDnc77oNau2Nb8U0weyGTRHit9zcE7ldNLCA1+Y+1cqJoHY1dL7gF7DsK7+/imysf0fGfibd+3K5Ga0r6GwH3CC3M1a5lw4nfdHi3p2nlJOHEv0iEcIzQNhXEJ7QcblTcP9WGv4VzEpP/Q0c77TckEDracZosuoJYwUImqXSKWrgCmL3SuBHv2MqbREneE9773t4ZWxO+otrRQYI1mpCwG4g3EOQEU7DRnBx2kA9rMhcsP3p3277MfZ91BkNTM4TMq/GWwq4W6pD4/3FNrzo6NChpAM1MUC0OGxjqJSAgwJK9YnOLdKjq62IttBGutmnnbmKWMfLg7+Hd3+z8kc3VdE1+EQpZ6ZaoJ2UFJVnJtBXg1uNivGKwE2IqYpnn8aStNqZIx9X0YHOfNE+Qn+83D/cPD2d/WmP/+LzdbvXMeTfPrmXm6W4zF0B/d/Lp4k7x08Xt0v8VWOtyHzNrMj9fs5jM9/6tXbZPN5Co+XXtb4HpL2hcGQiDBS29hW1Vk2xvoYhSvmNhja8V6ABMgYlySoWu4ygiOB3Zp1v8V8rp7zN/5L/pNEUx6QwskEhFqr1MNE03c6Wup4Cr+i2GMjGO22lMr5B6OaUUVe0TLIRts5BJ4ltKRawOnwCUJILHYB0QKCybzWA+LB6ZjFFFnd2BA+KlAuoujwBWI3R3SrbCMptYyDxqECGPmI+TeljVVQCN33r6GD2nMFeVAT0v44QJMSXiBwfU0uovsQyELbfqUKk8eDKJYilOA0UUcYVRfZAs5iBI0lErbCJuHWdgHqdK95Sjhl7YzCtFHVLHsUvZFKS9VDihFnSavEQVNK5YKIGD6gVE0xp7J1z8ZpqBzeV0izb+842kgGiOc+Hm9n6nOdzOA+HZ59bWc2YTW7DEcb0P8Km9vHUtUADo913FO5sllj3Deiq7s/WfCyGer7QHchzOkrJKgaKhmgAmmRYsW/3qOqssALzqZsAMZ5UGR5Q4qLiR9w/D814U+aHvnhcCSZPaU3/s7eOj8Ddh+H0Uq/avszQpvrycTf91+vt1+88ygOETAAA=') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-display: swap; font-weight: 800; src: url('data:font/woff2;base64,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') format('woff2'); }
/* ── 2. v2.0 base scale (unchanged) ─────────────────────────────────────── */
:root {
--ccl-charcoal: #2c2c30;
--ccl-charcoal-2: #36363a;
--ccl-charcoal-3: #1b1b1e;
--ccl-gold: #8f7ae0;
--ccl-gold-dim: #7a63cc;
--ccl-text: #f4f4f6;
--ccl-text-muted: #b2b2ba;
--ccl-border: #3d3d44;
--ccl-border-2: #4e4e57;
--ccl-green: #a9d88b;
--ccl-red: #f08b93;
--ccl-white: #ffffff;
--ccl-ink: #2a2431;
--ccl-grey: var(--ccl-charcoal);
--ccl-grey-2: var(--ccl-charcoal-2);
--ccl-grey-3: var(--ccl-charcoal-3);
--ccl-purple: var(--ccl-gold);
--ccl-purple-dim: var(--ccl-gold-dim);
--ccl-purple-wash: rgba(143, 122, 224, 0.12);
/* v3 additions to the base scale: tints derived from the v2.0 hues */
--ccl-gold-light: #a99af0; /* accent lifted to pass 4.5:1 as text on charcoal */
--ccl-violet-deep: #5b43b8; /* accent darkened to pass 4.5:1 on the light surface */
--ccl-charcoal-inset:#232327; /* between charcoal and charcoal-3: dark wells */
--ccl-amber: #e8c170; /* new: warning (v2.0 had none) */
--ccl-blue: #8fc3f0; /* new: informational / provenance */
--ccl-mist: #e4e2ea; /* light page: charcoal's hue, inverted */
--ccl-mist-2: #f1f0f5; /* light high surface */
--ccl-mist-3: #d9d6e1; /* light inset */
/* Typography, spacing and motion: unchanged from v2.0 */
--font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
--font-body: var(--font-mono);
--font-display: var(--font-mono);
--fw-regular: 400; --fw-medium: 500; --fw-bold: 700; --fw-display: 800;
--fs-caption: 11px; --fs-label: 12px; --fs-body: 14px; --fs-body-lg: 15px;
--fs-h3: 18px; --fs-h2: 22px; --fs-h1: 28px; --fs-display: 40px;
--lh-tight: 1.15; --lh-snug: 1.35; --lh-body: 1.7;
--tracking-wordmark: 0.02em; --tracking-caps: 0.08em; --tracking-caps-wide: 0.14em;
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px;
--space-6: 24px; --space-8: 32px; --space-10: 40px; --space-14: 56px; --space-16: 64px;
--ease-out: cubic-bezier(0.2, 0, 0, 1);
--dur-fast: 100ms; --dur-base: 160ms;
--dur-press: 60ms; /* v3: pressing reacts faster than hover */
--scrollbar-width: 6px;
/* ── 4a. Radius scale (v3; replaces v2.0's "0 is the rule") ── */
--radius-none: 0px; /* tables, code, grid lines: square stays available */
--radius-xs: 4px; /* chips, swatches, inline code */
--radius-sm: 8px; /* inputs, small buttons */
--radius-md: 12px; /* buttons, list rows */
--radius-lg: 18px; /* cards, panels */
--radius-xl: 26px; /* dialogs, the app shell */
--radius-pill: 999px; /* toggles, progress tracks, badges */
/* ── 4b. Shadow geometry: distance + blur per intensity level ── */
--nm-d-1: 2px; --nm-b-1: 5px; /* level 1: chips, small controls */
--nm-d-2: 4px; --nm-b-2: 10px; /* level 2: buttons, rows */
--nm-d-3: 8px; --nm-b-3: 18px; /* level 3: cards, panels */
--nm-d-4: 14px; --nm-b-4: 30px; /* level 4: dialogs */
/* Focus ring geometry: identical in both themes */
--focus-width: 2px;
--focus-offset: 3px;
--border-control-width: 1px;
--border-error-width: 2px;
}
/* ── 3. Theme tokens: DARK (default) ───────────────────────────────────── */
:root,
:root[data-theme="dark"] {
color-scheme: dark;
/* Surfaces */
--surface-page: var(--ccl-charcoal); /* #2c2c30 */
--surface-raised: var(--ccl-charcoal); /* v3: same as page; the lift comes from the shadow */
--surface-high: var(--ccl-charcoal-2); /* #36363a dialogs, menus */
--surface-inset: var(--ccl-charcoal-inset); /* #232327 inputs, wells, progress tracks */
--surface-code: var(--ccl-charcoal-3);
/* Text */
--text-primary: var(--ccl-text); /* 12.66:1 on page */
--text-secondary: var(--ccl-text-muted); /* 6.60:1 on page */
--text-accent: var(--ccl-gold-light); /* 5.67:1 on page */
--text-on-accent: var(--ccl-ink); /* on --accent-fill */
--text-on-gold: var(--ccl-ink);
/* Accent */
--accent: var(--ccl-gold); /* brand hue, for large marks only */
--accent-hover: var(--ccl-gold-dim);
--accent-fill: var(--ccl-gold-light); /* primary button fill; ink on it: 6.14:1 */
--accent-fill-press: #9785e6;
--accent-wash: rgba(169, 154, 240, 0.10);
/* Status: the v2.0 hues plus two new ones */
--status-success: var(--ccl-green);
--status-error: var(--ccl-red);
--status-warning: var(--ccl-amber);
--status-info: var(--ccl-blue);
--wash-success: rgba(169, 216, 139, 0.10);
--wash-error: rgba(240, 139, 147, 0.10);
--wash-warning: rgba(232, 193, 112, 0.10);
--wash-info: rgba(143, 195, 240, 0.10);
/* Borders */
--border-hairline: var(--ccl-border); /* decorative card edges */
--border-strong: var(--ccl-border-2);
--border-control: #85858f; /* 1.4.11: 3.81:1 page, 4.29:1 inset, 3.29:1 high */
--focus-ring: var(--ccl-gold-light); /* 5.67:1 on page */
/* ── 4c. Neumorphism shadow pairs, DARK ──
Dark soft UI fails when the "dark" shadow is only a darker charcoal:
nothing on #2c2c30 is visibly darker than #1b1b1e. Four rules make it
work here:
a. The dark half is true black at high alpha, not a darker gray.
b. The light half is white at 4–7% alpha. It reads as sheen, not glow.
c. Raised surfaces add a 1px top rim light (inset, white 6%). The rim
stays visible even where the drop shadow merges into the background.
d. Every control has a 3:1 border anyway, so the shadow never carries
structure on its own. */
--nm-shadow-dark: rgba(0, 0, 0, 0.62);
--nm-shadow-light: rgba(255, 255, 255, 0.055);
--nm-rim: inset 0 1px 0 rgba(255, 255, 255, 0.06);
--nm-inset-dark: rgba(0, 0, 0, 0.55);
--nm-inset-light: rgba(255, 255, 255, 0.045);
--nm-raised-gradient: linear-gradient(145deg, #313136, #29292d);
}
/* ── 3. Theme tokens: LIGHT (new in v3) ────────────────────────────────── */
@media (prefers-color-scheme: light) {
:root:not([data-theme="dark"]) {
color-scheme: light;
--surface-page: var(--ccl-mist);
--surface-raised: var(--ccl-mist);
--surface-high: var(--ccl-mist-2);
--surface-inset: var(--ccl-mist-3);
--surface-code: #d2cfdb;
--text-primary: var(--ccl-ink);
--text-secondary: #55505f;
--text-accent: var(--ccl-violet-deep);
--text-on-accent: var(--ccl-white);
--text-on-gold: var(--ccl-white);
--accent: var(--ccl-gold);
--accent-hover: var(--ccl-gold-dim);
--accent-fill: var(--ccl-violet-deep);
--accent-fill-press: #4d37a3;
--accent-wash: rgba(91, 67, 184, 0.10);
--status-success: #2c6619;
--status-error: #a8202f;
--status-warning: #7c5100;
--status-info: #1d5e94;
--wash-success: rgba(44, 102, 25, 0.10);
--wash-error: rgba(168, 32, 47, 0.10);
--wash-warning: rgba(124, 81, 0, 0.10);
--wash-info: rgba(29, 94, 148, 0.10);
--border-hairline: #cfccd8;
--border-strong: #b9b5c6;
--border-control: #736e86;
--focus-ring: var(--ccl-violet-deep);
--nm-shadow-dark: rgba(88, 80, 120, 0.30);
--nm-shadow-light: rgba(255, 255, 255, 0.95);
--nm-rim: inset 0 1px 0 rgba(255, 255, 255, 0.7);
--nm-inset-dark: rgba(88, 80, 120, 0.28);
--nm-inset-light: rgba(255, 255, 255, 0.9);
--nm-raised-gradient: linear-gradient(145deg, #eceaf1, #dcd9e3);
}
}
:root[data-theme="light"] {
color-scheme: light;
--surface-page: var(--ccl-mist);
--surface-raised: var(--ccl-mist);
--surface-high: var(--ccl-mist-2);
--surface-inset: var(--ccl-mist-3);
--surface-code: #d2cfdb;
--text-primary: var(--ccl-ink);
--text-secondary: #55505f;
--text-accent: var(--ccl-violet-deep);
--text-on-accent: var(--ccl-white);
--text-on-gold: var(--ccl-white);
--accent: var(--ccl-gold);
--accent-hover: var(--ccl-gold-dim);
--accent-fill: var(--ccl-violet-deep);
--accent-fill-press: #4d37a3;
--accent-wash: rgba(91, 67, 184, 0.10);
--status-success: #2c6619;
--status-error: #a8202f;
--status-warning: #7c5100;
--status-info: #1d5e94;
--wash-success: rgba(44, 102, 25, 0.10);
--wash-error: rgba(168, 32, 47, 0.10);
--wash-warning: rgba(124, 81, 0, 0.10);
--wash-info: rgba(29, 94, 148, 0.10);
--border-hairline: #cfccd8;
--border-strong: #b9b5c6;
--border-control: #736e86;
--focus-ring: var(--ccl-violet-deep);
--nm-shadow-dark: rgba(88, 80, 120, 0.30);
--nm-shadow-light: rgba(255, 255, 255, 0.95);
--nm-rim: inset 0 1px 0 rgba(255, 255, 255, 0.7);
--nm-inset-dark: rgba(88, 80, 120, 0.28);
--nm-inset-light: rgba(255, 255, 255, 0.9);
--nm-raised-gradient: linear-gradient(145deg, #eceaf1, #dcd9e3);
}
/* ── 4d. Composed shadows: theme-agnostic, built from the pairs above ── */
:root {
--nm-raised-1: calc(var(--nm-d-1) * -1) calc(var(--nm-d-1) * -1) var(--nm-b-1) var(--nm-shadow-light),
var(--nm-d-1) var(--nm-d-1) var(--nm-b-1) var(--nm-shadow-dark), var(--nm-rim);
--nm-raised-2: calc(var(--nm-d-2) * -1) calc(var(--nm-d-2) * -1) var(--nm-b-2) var(--nm-shadow-light),
var(--nm-d-2) var(--nm-d-2) var(--nm-b-2) var(--nm-shadow-dark), var(--nm-rim);
--nm-raised-3: calc(var(--nm-d-3) * -1) calc(var(--nm-d-3) * -1) var(--nm-b-3) var(--nm-shadow-light),
var(--nm-d-3) var(--nm-d-3) var(--nm-b-3) var(--nm-shadow-dark), var(--nm-rim);
--nm-raised-4: calc(var(--nm-d-4) * -1) calc(var(--nm-d-4) * -1) var(--nm-b-4) var(--nm-shadow-light),
var(--nm-d-4) var(--nm-d-4) var(--nm-b-4) var(--nm-shadow-dark), var(--nm-rim);
--nm-inset-1: inset var(--nm-d-1) var(--nm-d-1) var(--nm-b-1) var(--nm-inset-dark),
inset calc(var(--nm-d-1) * -1) calc(var(--nm-d-1) * -1) var(--nm-b-1) var(--nm-inset-light);
--nm-inset-2: inset var(--nm-d-2) var(--nm-d-2) var(--nm-b-2) var(--nm-inset-dark),
inset calc(var(--nm-d-2) * -1) calc(var(--nm-d-2) * -1) var(--nm-b-2) var(--nm-inset-light);
--nm-flat: none;
/* v2.0 names kept so old rules still resolve */
--shadow-none: none;
--shadow-raised: var(--nm-raised-2);
/* Borders, v2.0 names */
--border-width: 1px;
--border: var(--border-width) solid var(--border-hairline);
--border-strong-rule: var(--border-width) solid var(--border-strong);
--border-accent: 1.5px solid var(--accent);
--scrollbar-thumb: var(--border-strong);
--scrollbar-thumb-hover: var(--accent);
}
/* ── 6. Reference components ────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { background: var(--surface-page); }
body {
margin: 0;
background: var(--surface-page);
color: var(--text-primary);
font-family: var(--font-body);
font-size: var(--fs-body);
line-height: var(--lh-body);
-webkit-font-smoothing: antialiased;
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
/* Surfaces */
.nm-raised { background: var(--nm-raised-gradient); box-shadow: var(--nm-raised-3); border: 1px solid var(--border-hairline); border-radius: var(--radius-lg); }
.nm-raised-sm { background: var(--surface-raised); box-shadow: var(--nm-raised-2); border: 1px solid var(--border-hairline); border-radius: var(--radius-md); }
.nm-inset { background: var(--surface-inset); box-shadow: var(--nm-inset-2); border: 1px solid var(--border-hairline); border-radius: var(--radius-md); }
.nm-dialog { background: var(--surface-high); box-shadow: var(--nm-raised-4); border: 1px solid var(--border-strong); border-radius: var(--radius-xl); }
/* Buttons
* rest raised-2 + 1px control border
* hover border takes the accent color
* pressed inset shadow + accent wash fill + accent border (+ ✓ on toggles)
* focus 2px solid outline, offset 3px, in the focus color
* disabled no shadow, dashed border, secondary text, not-allowed cursor
*/
.btn {
font: var(--fw-medium) var(--fs-body)/1 var(--font-body);
color: var(--text-primary);
background: var(--surface-raised);
border: var(--border-control-width) solid var(--border-control);
border-radius: var(--radius-md);
padding: 10px 16px;
min-height: 40px;
box-shadow: var(--nm-raised-2);
cursor: pointer;
display: inline-flex; align-items: center; gap: var(--space-2);
transition: box-shadow var(--dur-base) var(--ease-out), border-color var(--dur-fast), background var(--dur-fast);
}
.btn:hover { border-color: var(--text-accent); }
.btn:active, .btn[aria-pressed="true"], .btn.is-pressed {
box-shadow: var(--nm-inset-1);
background: var(--accent-wash);
border-color: var(--text-accent);
transition-duration: var(--dur-press);
}
.btn[aria-pressed="true"]::before, .btn.is-pressed::before { content: "✓"; font-weight: var(--fw-bold); color: var(--text-accent); }
.btn:focus-visible, .btn.is-focused, .input:focus-visible, .input.is-focused, .select:focus-visible, .select.is-focused {
outline: var(--focus-width) solid var(--focus-ring);
outline-offset: var(--focus-offset);
}
.btn:disabled, .btn.is-disabled {
box-shadow: none;
border-style: dashed;
color: var(--text-secondary);
background: transparent;
cursor: not-allowed;
}
.btn-primary { background: var(--accent-fill); color: var(--text-on-accent); border-color: var(--accent-fill); font-weight: var(--fw-bold); }
.btn-primary:hover { border-color: var(--text-primary); }
.btn-primary:active, .btn-primary.is-pressed { background: var(--accent-fill-press); color: var(--text-on-accent); border-color: var(--text-primary); }
.btn-primary.is-pressed::before { color: var(--text-on-accent); }
.btn-danger { color: var(--status-error); border-color: var(--status-error); }
.btn-sm { min-height: 32px; padding: 6px 12px; font-size: var(--fs-label); border-radius: var(--radius-sm); box-shadow: var(--nm-raised-1); }
.btn-icon { width: 40px; padding: 0; justify-content: center; }
/* Inputs: always inset, always bordered */
.input, .select {
font: var(--fw-regular) var(--fs-body)/1.4 var(--font-body);
color: var(--text-primary);
background: var(--surface-inset);
border: var(--border-control-width) solid var(--border-control);
border-radius: var(--radius-sm);
box-shadow: var(--nm-inset-1);
padding: 9px 12px;
min-height: 40px;
width: 100%;
}
.input::placeholder { color: var(--text-secondary); }
.input:disabled, .input.is-disabled, .select:disabled {
box-shadow: none; border-style: dashed; color: var(--text-secondary); background: transparent;
}
/* Error: 2px red border + icon in the label + message. Never color alone. */
.field.has-error .input, .field.has-error .select, .input.is-error {
border: var(--border-error-width) solid var(--status-error);
padding: 8px 11px;
}
.field-error {
display: flex; gap: var(--space-2); align-items: flex-start;
color: var(--status-error); font-size: var(--fs-label); line-height: var(--lh-snug); margin-top: var(--space-1);
}
.field-error::before { content: "⚠"; font-weight: var(--fw-bold); }
/* Chips / badges: text + wash + border + glyph */
.chip {
display: inline-flex; align-items: center; gap: 6px;
font-size: var(--fs-caption); font-weight: var(--fw-bold);
letter-spacing: var(--tracking-caps); text-transform: uppercase;
padding: 2px 9px; border-radius: var(--radius-pill);
border: 1px solid currentColor; line-height: 1.6;
white-space: nowrap;
}
.chip-ok { color: var(--status-success); background: var(--wash-success); }
.chip-err { color: var(--status-error); background: var(--wash-error); }
.chip-warn { color: var(--status-warning); background: var(--wash-warning); }
.chip-info { color: var(--status-info); background: var(--wash-info); }
.chip-accent { color: var(--text-accent); background: var(--accent-wash); }
.chip-neutral { color: var(--text-secondary); background: transparent; }
.chip-dashed { border-style: dashed; }
/* Progress track (inset) + fill (raised) */
.track { height: 10px; border-radius: var(--radius-pill); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border: 1px solid var(--border-hairline); overflow: hidden; }
.track > span { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--text-accent); }
.track.is-low > span { background: var(--status-error); }
/* Swatch: 1–3 colors, a hairline so white/black filament shows on either theme */
.swatch { display: inline-flex; width: 26px; height: 26px; border-radius: 50%; overflow: hidden; border: 1px solid var(--border-control); box-shadow: var(--nm-raised-1); flex: none; }
.swatch > i { flex: 1; }
.swatch-sm { width: 18px; height: 18px; }
/* Text helpers */
.muted { color: var(--text-secondary); }
.accent { color: var(--text-accent); }
.caps { text-transform: uppercase; letter-spacing: var(--tracking-caps-wide); font-size: var(--fs-caption); font-weight: var(--fw-bold); }
.num { font-variant-numeric: tabular-nums; }
/* ── Mockup app shell (shared by all four screens) ── */
.shell { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: var(--space-6); max-width: 1440px; margin: 0 auto; padding: var(--space-6); min-height: 100vh; }
.rail { position: sticky; top: var(--space-6); align-self: start; padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-5); }
.wordmark { font-weight: var(--fw-display); font-size: var(--fs-h3); letter-spacing: var(--tracking-wordmark); display: flex; align-items: center; gap: var(--space-2); }
.wordmark-mark { width: 30px; height: 30px; border-radius: 10px; background: var(--accent-fill); color: var(--text-on-accent); display: grid; place-items: center; font-size: 15px; box-shadow: var(--nm-raised-1); border: 1px solid var(--border-control); }
.nav { display: flex; flex-direction: column; gap: var(--space-2); }
.nav a { display: flex; align-items: center; gap: var(--space-3); padding: 10px 12px; border-radius: var(--radius-md); color: var(--text-primary); text-decoration: none; border: 1px solid transparent; font-weight: var(--fw-medium); }
.nav a:hover { border-color: var(--border-control); }
.nav a:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: var(--focus-offset); }
.nav a[aria-current="page"] { background: var(--surface-inset); box-shadow: var(--nm-inset-1); border-color: var(--text-accent); color: var(--text-accent); font-weight: var(--fw-bold); }
.nav svg { width: 18px; height: 18px; flex: none; }
.nav .nav-new { margin-left: auto; }
.rail-foot { display: flex; flex-direction: column; gap: var(--space-3); border-top: 1px solid var(--border-hairline); padding-top: var(--space-4); }
.seg { display: inline-flex; padding: 4px; gap: 4px; border-radius: var(--radius-pill); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border: 1px solid var(--border-control); }
.seg button { font: var(--fw-medium) var(--fs-label)/1 var(--font-body); color: var(--text-secondary); background: transparent; border: 1px solid transparent; border-radius: var(--radius-pill); padding: 7px 12px; cursor: pointer; display: inline-flex; gap: 6px; align-items: center; }
.seg button[aria-pressed="true"] { background: var(--surface-raised); color: var(--text-primary); box-shadow: var(--nm-raised-1); border-color: var(--border-control); font-weight: var(--fw-bold); }
.seg button[aria-pressed="true"]::before { content: "✓"; color: var(--text-accent); }
.seg button:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; }
.who { font-size: var(--fs-label); }
main { min-width: 0; display: flex; flex-direction: column; gap: var(--space-6); padding-bottom: var(--space-16); }
.proposal { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); align-items: center; font-size: var(--fs-label); color: var(--text-secondary); padding: var(--space-3) var(--space-4); }
.page-head { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-end; justify-content: space-between; }
.page-head h1 { margin: 0; font-size: var(--fs-h1); line-height: var(--lh-tight); font-weight: var(--fw-display); }
.page-head p { margin: var(--space-1) 0 0; }
.actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
h2.section { font-size: var(--fs-label); text-transform: uppercase; letter-spacing: var(--tracking-caps-wide); color: var(--text-secondary); margin: 0 0 var(--space-3); font-weight: var(--fw-bold); display: flex; align-items: center; gap: var(--space-2); }
.card { padding: var(--space-5); }
.card h3 { margin: 0; font-size: var(--fs-body-lg); }
.grid { display: grid; gap: var(--space-5); }
.stack { display: flex; flex-direction: column; gap: var(--space-3); }
.row { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }
.spacer { flex: 1; }
a { color: var(--text-accent); }
a:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; border-radius: 4px; }
small, .small { font-size: var(--fs-label); }
.tiny { font-size: var(--fs-caption); }
code { font-family: var(--font-mono); font-size: 0.92em; background: var(--surface-inset); padding: 1px 5px; border-radius: var(--radius-xs); border: 1px solid var(--border-hairline); }
.kbd-note { font-size: var(--fs-caption); color: var(--text-secondary); }
/* Data tables: square, numbers right-aligned, inside a soft card */
.table-wrap { overflow-x: auto; margin: 0 calc(var(--space-5) * -1); padding: 0 var(--space-5); }
table.tbl { width: 100%; border-collapse: collapse; border-radius: var(--radius-none); font-size: 13px; }
.tbl th { text-align: left; font-size: var(--fs-caption); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--text-secondary); font-weight: var(--fw-bold); padding: 10px 10px; border-bottom: 1px solid var(--border-strong); white-space: nowrap; }
.tbl td { padding: 11px 10px; border-bottom: 1px solid var(--border-hairline); vertical-align: middle; }
.tbl tr:last-child td { border-bottom: 0; }
.tbl .r { text-align: right; font-variant-numeric: tabular-nums; }
.tbl tbody tr:hover td { background: var(--accent-wash); }
/* Provenance marker used across screens */
.src { display: inline-flex; gap: 4px; align-items: center; font-size: var(--fs-caption); font-weight: var(--fw-bold); letter-spacing: var(--tracking-caps); text-transform: uppercase; }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: none; }
/* Stat tiles */
.stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-5); }
.stat { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-1); }
.stat-value { font-size: 30px; font-weight: var(--fw-display); line-height: var(--lh-tight); font-variant-numeric: tabular-nums; }
.stat-label { font-size: var(--fs-label); color: var(--text-secondary); text-transform: uppercase; letter-spacing: var(--tracking-caps); font-weight: var(--fw-bold); }
.stat-foot { font-size: var(--fs-label); color: var(--text-secondary); }
.stat.warn .stat-value { color: var(--status-warning); }
/* Modal backdrop for dialogs */
.scrim { position: fixed; inset: 0; background: rgba(10, 10, 14, 0.55); }
:root[data-theme="light"] .scrim { background: rgba(60, 55, 80, 0.35); }
/* Responsive */
@media (max-width: 1100px) { .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 860px) {
.shell { grid-template-columns: 1fr; padding: var(--space-4); gap: var(--space-4); }
.rail { position: static; flex-direction: row; flex-wrap: wrap; align-items: center; padding: var(--space-3) var(--space-4); gap: var(--space-3); }
.nav { flex-direction: row; flex-wrap: wrap; gap: var(--space-1); }
.nav a { padding: 8px 10px; }
.nav a span.lbl { display: none; }
.nav a[aria-current="page"] span.lbl { display: inline; }
.nav .nav-new { display: none; }
.rail-foot { border: 0; padding: 0; flex-direction: row; margin-left: auto; }
.who { display: none; }
}
@media (max-width: 520px) {
.stats { grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.stat { padding: var(--space-4); }
.stat-value { font-size: 22px; }
.page-head h1 { font-size: var(--fs-h2); }
}
a.btn { text-decoration: none; }
.th-note { display: block; margin-top: 4px; }
/* ── Design System v3.1 components (iteration 2) ─────────────────────────
* Built only from design-system-v3.css tokens. No new colors. */
/* Shell */
.shell { display: grid; grid-template-columns: 224px minmax(0, 1fr); gap: var(--space-6); max-width: 1480px; margin: 0 auto; padding: var(--space-5) var(--space-6); min-height: 100vh; }
.rail { position: sticky; top: var(--space-5); align-self: start; padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-4); max-height: calc(100vh - 40px); }
.wordmark { font-weight: var(--fw-display); font-size: var(--fs-h3); display: flex; align-items: center; gap: var(--space-2); padding: 4px 6px; }
.wordmark-mark { width: 30px; height: 30px; border-radius: 10px; background: var(--accent-fill); color: var(--text-on-accent); display: grid; place-items: center; font-size: 15px; border: 1px solid var(--border-control); box-shadow: var(--nm-raised-1); }
.nav-group { display: flex; flex-direction: column; gap: 4px; }
.nav-label { font-size: var(--fs-caption); text-transform: uppercase; letter-spacing: var(--tracking-caps-wide); color: var(--text-secondary); font-weight: var(--fw-bold); padding: 8px 12px 2px; }
.nav a { display: flex; align-items: center; gap: var(--space-3); padding: 9px 12px; border-radius: var(--radius-md); color: var(--text-primary); text-decoration: none; border: 1px solid transparent; font-weight: var(--fw-medium); position: relative; }
.nav a:hover { border-color: var(--border-control); }
.nav a:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; }
.nav a[aria-current="page"] { background: var(--surface-inset); box-shadow: var(--nm-inset-1); border-color: var(--text-accent); color: var(--text-accent); font-weight: var(--fw-bold); }
.nav svg { width: 18px; height: 18px; flex: none; }
.nav .count { margin-left: auto; min-width: 22px; height: 20px; padding: 0 6px; border-radius: var(--radius-pill); font-size: var(--fs-caption); font-weight: var(--fw-bold); display: inline-grid; place-items: center; border: 1px solid currentColor; }
.count-warn { color: var(--status-warning); background: var(--wash-warning); }
.count-err { color: var(--status-error); background: var(--wash-error); }
.rail-foot { margin-top: auto; display: flex; flex-direction: column; gap: var(--space-3); border-top: 1px solid var(--border-hairline); padding-top: var(--space-3); }
/* Top bar: search, freshness, context */
.topbar { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }
.search-trigger { flex: 1; min-width: 220px; max-width: 560px; display: flex; align-items: center; gap: var(--space-3); padding: 9px 14px; border-radius: var(--radius-pill); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border: 1px solid var(--border-control); color: var(--text-secondary); font: inherit; cursor: pointer; text-align: left; }
.search-trigger:hover { border-color: var(--text-accent); }
.search-trigger:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: var(--focus-offset); }
.search-trigger svg { width: 16px; height: 16px; }
.kbd { font: var(--fw-bold) 10px/1 var(--font-mono); padding: 3px 6px; border-radius: 5px; border: 1px solid var(--border-control); color: var(--text-secondary); background: var(--surface-raised); box-shadow: 0 1px 0 var(--border-strong); }
.fresh { display: inline-flex; align-items: center; gap: 8px; font-size: var(--fs-label); color: var(--text-secondary); }
.fresh .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--status-success); box-shadow: 0 0 0 3px var(--wash-success); }
.fresh.is-stale .dot { background: var(--status-warning); box-shadow: 0 0 0 3px var(--wash-warning); }
.fresh.is-stale { color: var(--status-warning); }
/* Breadcrumb */
.crumbs { display: flex; gap: 6px; align-items: center; font-size: var(--fs-label); color: var(--text-secondary); }
.crumbs a { color: var(--text-secondary); text-decoration: none; }
.crumbs a:hover { color: var(--text-accent); text-decoration: underline; }
/* Page header: title, one-line summary, ONE primary action, overflow for the rest */
.page-head { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-end; justify-content: space-between; }
.page-head h1 { margin: 0; font-size: var(--fs-h1); line-height: var(--lh-tight); font-weight: var(--fw-display); }
.page-head .sum { margin: 6px 0 0; color: var(--text-secondary); font-size: 13px; }
.page-head .sum b { color: var(--text-primary); }
/* Overflow / row menu */
.menu-wrap { position: relative; display: inline-block; }
.menu { position: absolute; right: 0; top: calc(100% + 6px); z-index: 30; min-width: 220px; padding: 6px; display: none; flex-direction: column; gap: 2px; background: var(--surface-high); border: 1px solid var(--border-strong); border-radius: var(--radius-md); box-shadow: var(--nm-raised-3); }
.menu.is-open { display: flex; }
.menu button, .menu a { all: unset; box-sizing: border-box; display: flex; gap: 10px; align-items: center; padding: 8px 10px; border-radius: var(--radius-sm); font-size: 13px; cursor: pointer; color: var(--text-primary); }
.menu button:hover, .menu a:hover, .menu button:focus-visible, .menu a:focus-visible { background: var(--accent-wash); outline: 1px solid var(--text-accent); }
.menu .danger { color: var(--status-error); }
.menu hr { border: 0; border-top: 1px solid var(--border-hairline); margin: 4px 0; width: 100%; }
.menu .hint { margin-left: auto; font-size: var(--fs-caption); color: var(--text-secondary); }
/* Tabs (segmented, with counts) */
.tabs { display: flex; gap: 4px; padding: 4px; border-radius: var(--radius-pill); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border: 1px solid var(--border-control); width: max-content; max-width: 100%; overflow-x: auto; }
.tabs button { font: var(--fw-medium) 13px/1 var(--font-body); color: var(--text-secondary); background: transparent; border: 1px solid transparent; border-radius: var(--radius-pill); padding: 8px 14px; cursor: pointer; display: inline-flex; gap: 8px; align-items: center; white-space: nowrap; }
.tabs button[aria-selected="true"] { background: var(--surface-raised); color: var(--text-primary); font-weight: var(--fw-bold); box-shadow: var(--nm-raised-1); border-color: var(--border-control); }
.tabs button:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; }
.tabs .n { font-size: var(--fs-caption); padding: 1px 7px; border-radius: var(--radius-pill); border: 1px solid currentColor; }
.tabs .n.warn { color: var(--status-warning); }
/* Filter chips (removable) */
.fchips { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; }
.fchip { display: inline-flex; gap: 6px; align-items: center; padding: 4px 6px 4px 10px; border-radius: var(--radius-pill); border: 1px solid var(--text-accent); background: var(--accent-wash); color: var(--text-accent); font-size: var(--fs-label); font-weight: var(--fw-bold); }
.fchip button { all: unset; cursor: pointer; width: 18px; height: 18px; display: grid; place-items: center; border-radius: 50%; }
.fchip button:hover, .fchip button:focus-visible { background: var(--text-accent); color: var(--text-on-accent); }
.fadd { font-size: var(--fs-label); }
/* Quiet provenance: icon + lowercase text, never a chip */
.prov { display: inline-flex; gap: 4px; align-items: center; font-size: var(--fs-caption); color: var(--text-secondary); white-space: nowrap; }
.prov i { font-style: normal; width: 14px; text-align: center; }
.prov.warn { color: var(--status-warning); font-weight: var(--fw-bold); }
.prov.info { color: var(--status-info); }
/* Status: small filled label + glyph. Reserved for state, not provenance */
.st { display: inline-flex; gap: 6px; align-items: center; font-size: var(--fs-label); font-weight: var(--fw-bold); white-space: nowrap; }
.st::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }
.st.run { color: var(--text-accent); } .st.ok { color: var(--status-success); } .st.err { color: var(--status-error); } .st.warn { color: var(--status-warning); } .st.idle { color: var(--text-secondary); }
.st.warn::before { border-radius: 2px; transform: rotate(45deg); }
.st.err::before { border-radius: 1px; }
.st.idle::before { background: transparent; border: 2px solid currentColor; width: 6px; height: 6px; }
/* Data tables (v3.1): quieter, row = one line where possible */
.tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.tbl th { text-align: left; font-size: var(--fs-caption); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--text-secondary); font-weight: var(--fw-bold); padding: 10px 12px; border-bottom: 1px solid var(--border-strong); white-space: nowrap; position: sticky; top: 0; background: var(--surface-raised); z-index: 1; }
.tbl th button.sort { all: unset; cursor: pointer; display: inline-flex; gap: 4px; align-items: center; }
.tbl th button.sort:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; border-radius: 3px; }
.tbl th[aria-sort="ascending"] button.sort::after { content: "▲"; font-size: 9px; color: var(--text-accent); }
.tbl th[aria-sort="descending"] button.sort::after { content: "▼"; font-size: 9px; color: var(--text-accent); }
.tbl th[aria-sort="none"] button.sort::after { content: "↕"; font-size: 10px; opacity: .6; }
.tbl td { padding: 10px 12px; border-bottom: 1px solid var(--border-hairline); vertical-align: middle; }
.tbl tr:last-child td { border-bottom: 0; }
.tbl .r { text-align: right; font-variant-numeric: tabular-nums; }
.tbl tbody tr.clickable { cursor: pointer; }
.tbl tbody tr.clickable:hover td { background: var(--accent-wash); }
.tbl tbody tr.is-selected td { background: var(--accent-wash); box-shadow: inset 0 1px 0 var(--text-accent), inset 0 -1px 0 var(--text-accent); }
.tbl tbody tr.is-selected td:first-child { box-shadow: inset 3px 0 0 var(--text-accent), inset 0 1px 0 var(--text-accent), inset 0 -1px 0 var(--text-accent); }
.tbl tbody tr:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: -2px; }
.sub { display: block; font-size: var(--fs-caption); color: var(--text-secondary); font-weight: var(--fw-regular); line-height: var(--lh-snug); }
.strong { font-weight: var(--fw-bold); }
.num { font-variant-numeric: tabular-nums; }
.table-card { padding: 0; overflow: hidden; }
.table-scroll { overflow: auto; max-height: 70vh; }
.table-foot { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-top: 1px solid var(--border-hairline); flex-wrap: wrap; font-size: var(--fs-label); }
/* Meter: remaining bar with the 200 g threshold tick */
.meter { position: relative; height: 8px; border-radius: var(--radius-pill); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border: 1px solid var(--border-hairline); overflow: visible; min-width: 90px; }
.meter > span { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--text-accent); }
.meter.is-low > span { background: var(--status-warning); }
.meter .tick { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--text-secondary); border-radius: 1px; }
/* Drawer (right sheet; full-screen on phones) */
.drawer-scrim { position: fixed; inset: 0; background: rgba(10, 10, 14, .5); opacity: 0; pointer-events: none; transition: opacity var(--dur-base) var(--ease-out); z-index: 40; }
:root[data-theme="light"] .drawer-scrim { background: rgba(60, 55, 80, .28); }
.drawer { position: fixed; top: 12px; right: 12px; bottom: 12px; width: min(520px, calc(100vw - 24px)); z-index: 41; transform: translateX(calc(100% + 24px)); transition: transform 220ms var(--ease-out); display: flex; flex-direction: column; overflow: hidden; }
body.drawer-open .drawer { transform: none; }
body.drawer-open .drawer-scrim { opacity: 1; pointer-events: auto; }
.drawer-head { padding: var(--space-5) var(--space-5) var(--space-3); display: flex; gap: var(--space-3); align-items: flex-start; border-bottom: 1px solid var(--border-hairline); }
.drawer-head h2 { margin: 0; font-size: var(--fs-h3); line-height: var(--lh-snug); }
.drawer-tabs { padding: var(--space-3) var(--space-5) 0; }
.drawer-body { flex: 1; overflow: auto; padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-5); }
.drawer-foot { padding: var(--space-4) var(--space-5); border-top: 1px solid var(--border-hairline); display: flex; gap: var(--space-3); justify-content: flex-end; align-items: center; flex-wrap: wrap; }
.drawer-nav { display: flex; gap: 4px; }
@media (prefers-reduced-motion: reduce) { .drawer, .drawer-scrim { transition: none; } }
/* Key-value list */
.kv { display: grid; grid-template-columns: minmax(110px, auto) 1fr; gap: 8px var(--space-4); margin: 0; font-size: 13px; }
.kv dt { color: var(--text-secondary); }
.kv dd { margin: 0; font-variant-numeric: tabular-nums; }
.panel { padding: var(--space-4); }
.panel h3 { margin: 0 0 var(--space-3); font-size: var(--fs-label); text-transform: uppercase; letter-spacing: var(--tracking-caps-wide); color: var(--text-secondary); }
/* Command palette */
.pal-scrim { position: fixed; inset: 0; background: rgba(10, 10, 14, .55); z-index: 60; display: none; align-items: flex-start; justify-content: center; padding-top: 12vh; }
:root[data-theme="light"] .pal-scrim { background: rgba(60, 55, 80, .3); }
.pal-scrim.is-open { display: flex; }
.pal { width: min(640px, calc(100vw - 32px)); max-height: 70vh; display: flex; flex-direction: column; overflow: hidden; }
.pal-input { display: flex; gap: var(--space-3); align-items: center; padding: var(--space-4); border-bottom: 1px solid var(--border-hairline); }
.pal-input input { all: unset; flex: 1; font: var(--fw-medium) 16px/1.4 var(--font-body); color: var(--text-primary); }
.pal-input input::placeholder { color: var(--text-secondary); }
.pal-list { overflow: auto; padding: 6px; }
.pal-sec { font-size: var(--fs-caption); text-transform: uppercase; letter-spacing: var(--tracking-caps-wide); color: var(--text-secondary); font-weight: var(--fw-bold); padding: 10px 10px 4px; }
.pal-item { display: flex; gap: var(--space-3); align-items: center; padding: 9px 10px; border-radius: var(--radius-sm); cursor: pointer; font-size: 13px; border: 1px solid transparent; }
.pal-item[aria-selected="true"] { background: var(--accent-wash); border-color: var(--text-accent); }
.pal-item .meta { margin-left: auto; font-size: var(--fs-caption); color: var(--text-secondary); white-space: nowrap; }
.pal-foot { padding: 8px var(--space-4); border-top: 1px solid var(--border-hairline); display: flex; gap: var(--space-4); font-size: var(--fs-caption); color: var(--text-secondary); flex-wrap: wrap; }
/* Toasts */
.toasts { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 70; display: flex; flex-direction: column; gap: 8px; align-items: center; pointer-events: none; }
.toast { pointer-events: auto; display: flex; gap: var(--space-3); align-items: center; padding: 10px 12px 10px 16px; background: var(--surface-high); border: 1px solid var(--border-strong); border-left: 4px solid var(--status-success); border-radius: var(--radius-md); box-shadow: var(--nm-raised-3); font-size: 13px; max-width: min(560px, calc(100vw - 32px)); }
.toast.warn { border-left-color: var(--status-warning); }
/* Attention list (dashboard) */
.attn-list { display: flex; flex-direction: column; gap: var(--space-3); }
.attn { display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; gap: var(--space-4); align-items: center; padding: var(--space-4); border-radius: var(--radius-md); background: var(--surface-raised); border: 1px solid var(--border-hairline); box-shadow: var(--nm-raised-2); }
.attn .ico { width: 44px; height: 44px; border-radius: 12px; display: grid; place-items: center; font-size: 20px; font-weight: var(--fw-bold); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border: 1px solid var(--border-hairline); }
.attn.warn .ico { color: var(--status-warning); border-color: var(--status-warning); }
.attn.err .ico { color: var(--status-error); border-color: var(--status-error); }
.attn.info .ico { color: var(--status-info); }
.attn h3 { margin: 0; font-size: 14px; }
.attn p { margin: 2px 0 0; font-size: var(--fs-label); color: var(--text-secondary); }
.attn-done { padding: var(--space-5); text-align: center; color: var(--text-secondary); }
/* Skeleton + empty + error states */
.skel { border-radius: 6px; background: linear-gradient(90deg, var(--surface-inset) 0%, var(--border-hairline) 50%, var(--surface-inset) 100%); background-size: 200% 100%; animation: skel 1.4s linear infinite; height: 12px; }
@keyframes skel { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }
.empty { padding: var(--space-8) var(--space-5); text-align: center; display: flex; flex-direction: column; gap: var(--space-3); align-items: center; }
.empty h3 { margin: 0; font-size: 15px; }
.empty p { margin: 0; color: var(--text-secondary); font-size: 13px; max-width: 420px; }
.banner { display: flex; gap: var(--space-3); align-items: center; padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); font-size: 13px; border: 1px solid var(--status-warning); background: var(--wash-warning); }
.banner.err { border-color: var(--status-error); background: var(--wash-error); }
/* Slot grid (printers + move flow) */
.slotgrid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.slotgrid.one { grid-template-columns: minmax(0, 1fr); max-width: 25%; }
.slot { all: unset; box-sizing: border-box; cursor: pointer; display: flex; flex-direction: column; gap: 6px; align-items: flex-start; padding: 10px; min-height: 92px; border-radius: var(--radius-md); border: 1px solid var(--border-control); background: var(--surface-raised); box-shadow: var(--nm-raised-1); font-size: var(--fs-caption); position: relative; min-width: 0; }
.slot:hover { border-color: var(--text-accent); }
.slot:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; }
.slot .sn { color: var(--text-secondary); font-weight: var(--fw-bold); }
.slot .nm { font-weight: var(--fw-bold); font-size: 12px; line-height: var(--lh-snug); overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.slot .g { margin-top: auto; font-variant-numeric: tabular-nums; font-size: 12px; }
.slot.empty { border-style: dashed; box-shadow: none; background: transparent; color: var(--text-secondary); justify-content: center; align-items: center; text-align: center; }
.slot.is-low { border-color: var(--status-warning); }
.slot[aria-pressed="true"] { background: var(--accent-wash); border: 2px solid var(--text-accent); box-shadow: var(--nm-inset-1); }
.slot[aria-pressed="true"]::after { content: "✓"; position: absolute; top: 6px; right: 8px; color: var(--text-accent); font-weight: var(--fw-bold); font-size: 13px; }
.slot[disabled] { cursor: not-allowed; opacity: .75; }
/* Mockup pill (replaces the iteration-1 banner) */
.mock { position: fixed; left: 16px; bottom: 16px; z-index: 35; }
.mock > button { font: var(--fw-bold) var(--fs-caption)/1 var(--font-body); text-transform: uppercase; letter-spacing: var(--tracking-caps); padding: 8px 12px; border-radius: var(--radius-pill); border: 1px solid var(--text-accent); background: var(--surface-high); color: var(--text-accent); box-shadow: var(--nm-raised-2); cursor: pointer; }
.mock .menu { left: 0; right: auto; top: auto; bottom: calc(100% + 8px); width: 330px; padding: var(--space-4); gap: var(--space-2); font-size: var(--fs-label); }
.mock .menu p { margin: 0; line-height: var(--lh-snug); }
/* Mobile bottom tab bar + FAB */
.tabbar { display: none; }
.fab { display: none; }
@media (max-width: 699px) {
.shell { grid-template-columns: minmax(0, 1fr); padding: var(--space-3) var(--space-4) 96px; gap: var(--space-4); }
.rail { display: none; }
.tabbar { display: grid; grid-template-columns: repeat(4, 1fr); position: fixed; left: 8px; right: 8px; bottom: 8px; z-index: 36; padding: 6px; border-radius: var(--radius-xl); }
.tabbar a { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 0; border-radius: var(--radius-lg); color: var(--text-secondary); text-decoration: none; font-size: 11px; font-weight: var(--fw-medium); position: relative; border: 1px solid transparent; }
.tabbar a[aria-current="page"] { color: var(--text-accent); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border-color: var(--text-accent); font-weight: var(--fw-bold); }
.tabbar svg { width: 20px; height: 20px; }
.tabbar .count { position: absolute; top: 2px; right: calc(50% - 22px); min-width: 16px; height: 16px; font-size: 9px; padding: 0 4px; border-radius: 99px; display: grid; place-items: center; border: 1px solid currentColor; }
.fab { display: grid; place-items: center; position: fixed; right: 16px; bottom: 88px; z-index: 36; width: 56px; height: 56px; border-radius: 18px; font-size: 26px; padding: 0; }
.mock { bottom: 88px; }
.topbar .fresh span.long { display: none; }
.page-head .primary-desktop { display: none; }
.drawer { top: 0; right: 0; bottom: 0; width: 100vw; border-radius: 0; }
.slotgrid.one { max-width: 50%; }
}
@media (max-width: 520px) { .slotgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Form grid + small utilities */
.fr2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px 16px; }
.nowrap { white-space: nowrap; }
.drawer-body a { color: var(--text-accent); }
.linkish { all: unset; cursor: pointer; color: var(--text-accent); text-decoration: underline; }
.linkish:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; }
.tile-link { text-decoration: none; color: inherit; }
.tile-link:hover { border-color: var(--text-accent); }
.tile-link:focus-visible { outline: var(--focus-width) solid var(--focus-ring); outline-offset: var(--focus-offset); }
.is-flash { animation: flash 1.6s var(--ease-out) 1; }
@keyframes flash { 0%, 40% { outline: 3px solid var(--focus-ring); outline-offset: 4px; } 100% { outline: 3px solid transparent; outline-offset: 4px; } }
@media (prefers-reduced-motion: reduce) { .is-flash { animation: none; outline: 3px solid var(--focus-ring); } }
#page { display: flex; flex-direction: column; gap: var(--space-6); min-width: 0; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
#drawer-title:focus { outline: none; }
#drawer-title:focus-visible { outline: none; text-decoration: underline; text-decoration-color: var(--focus-ring); text-underline-offset: 4px; }
.short { display: none; }
@media (max-width: 699px) {
.search-trigger .long, .search-trigger .kbd.long, .mock .long { display: none; }
.search-trigger .short { display: inline; }
.search-trigger { min-width: 0; }
.remcell .top { flex-wrap: nowrap; white-space: nowrap; }
.remcell .top .sub { display: none !important; }
}
.pal-input svg { width: 18px; height: 18px; flex: none; color: var(--text-secondary); }
/* ── Tablet tier (700–1180 px): compact rail, side-sheet panel ───────────── */
@media (min-width: 700px) and (max-width: 1180px) {
.shell { grid-template-columns: 88px minmax(0, 1fr); gap: var(--space-5); padding: var(--space-4) var(--space-5); }
.rail { padding: var(--space-3) 8px; gap: var(--space-3); align-items: stretch; }
.wordmark { justify-content: center; font-size: 0; padding: 4px 0; }
.wordmark-mark { width: 40px; height: 40px; font-size: 18px; }
.nav-label { font-size: 9px; padding: 6px 0 0; text-align: center; letter-spacing: .06em; }
.nav a { flex-direction: column; gap: 4px; padding: 10px 2px 8px; font-size: 11px; text-align: center; justify-content: center; }
.nav a svg { width: 22px; height: 22px; }
.nav a > span:not(.count) { line-height: 1.1; }
.nav a .sub { display: none; }
.nav .count { position: absolute; top: 4px; right: 10px; margin: 0; min-width: 18px; height: 18px; font-size: 10px; padding: 0 4px; }
.rail-foot .seg, .rail-foot .small { display: none; }
.rail-foot { border-top: 0; padding-top: 0; }
.drawer { width: min(480px, calc(100vw - 96px)); }
.hide-t { display: none !important; }
.page-head h1 { font-size: var(--fs-h2); }
}
/* Tablet touch targets: at least 44 px for primary interactive rows */
@media (pointer: coarse) {
.btn-sm { min-height: 40px; }
.tbl td { padding-top: 12px; padding-bottom: 12px; }
.menu button, .menu a { padding: 12px 12px; }
.kbd { display: none; }
}
.more-sheet { position: fixed; left: 8px; right: 8px; bottom: 84px; top: auto; z-index: 37; padding: 8px; }
.more-sheet a svg, .more-sheet button svg { width: 18px; height: 18px; }
.findit { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; padding: 12px 14px; border-radius: var(--radius-md); border: 2px solid var(--text-accent); background: var(--accent-wash); }
.findit b { font-size: 17px; }
.findit .sub { width: 100%; text-transform: uppercase; letter-spacing: var(--tracking-caps-wide); font-weight: 700; }
details.chg { margin-top: 8px; }
details.chg summary { cursor: pointer; font-size: var(--fs-label); color: var(--text-accent); font-weight: 700; }
.holder { padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); background: var(--surface-inset); box-shadow: var(--nm-inset-1); border: 1px solid var(--border-hairline); display: flex; flex-direction: column; gap: 8px; }
.holder-h { display: flex; gap: var(--space-3); align-items: center; font-size: var(--fs-label); flex-wrap: wrap; }
.tabbar { grid-template-columns: repeat(5, 1fr) !important; }
.map { padding: var(--space-5); }
.map svg { width: 100%; height: auto; display: block; }
.map .node rect { fill: var(--surface-raised); stroke: var(--border-control); stroke-width: 1.5; }
.map .node.hub rect { fill: var(--accent-wash); stroke: var(--text-accent); stroke-width: 2; }
.map .node.page rect { stroke: var(--text-primary); }
.map text { fill: var(--text-primary); font-family: var(--font-mono); font-size: 13px; }
.map text.s { fill: var(--text-secondary); font-size: 11px; }
.map .e { stroke: var(--text-secondary); stroke-width: 1.5; fill: none; }
.map .e.hot { stroke: var(--text-accent); stroke-width: 2; }
.map .lbl { fill: var(--text-secondary); font-size: 10.5px; }
.map a:focus-visible rect { stroke: var(--focus-ring); stroke-width: 3; }
.flows { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 330px), 1fr)); gap: var(--space-4); }
.flow { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-3); }
.flow h3 { margin: 0; font-size: 15px; }
.flow ol { margin: 0; padding-left: 20px; font-size: 13px; color: var(--text-secondary); display: flex; flex-direction: column; gap: 4px; }
.flow ol b { color: var(--text-primary); }
.flow .btn { align-self: flex-start; }
.compare { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: var(--space-4); }
.compare > div { padding: var(--space-4); font-size: 13px; }
.compare h3 { margin: 0 0 8px; font-size: var(--fs-label); text-transform: uppercase; letter-spacing: var(--tracking-caps-wide); color: var(--text-secondary); }
.compare ul { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 4px; }
</style>
</head>
<body>
<script>
/* Sample data for the iteration-2 mockups. One model shared by every page, so a
* spool, print or printer is the same object wherever it appears. Values are
* based on the real inventory (import/filament_review.tsv, seed.sql spool
* types) and the 2026-08-12 production canary. Nothing here is live. */
var NOW = new Date('2026-09-18T09:41:07');
var CANARY = { spools: 105, brands: 18, kg: 95.72, value: 1721.18 };
/* tsrc: where this spool's tare came from.
* 'spool' weighed for this reel (tare_origin=spool)
* 'manufacturer' | 'community' | 'estimated' via the chosen spool type
* null no tare known */
var SPOOLS = [
{ id: 40, c: ['#1f3fbf'], color: 'Klein Blue', brand: 'Sunlu', speed: null, mat: 'PLA', type: '+ 2.0', fin: 'Basic', rem: 64, tot: 250, tare: 60, tsrc: 'community', stype: 'Sunlu — 250 g mini', remSrc: 'typed', kg: 25.20, cont: null, loc: 'Shelf B2', label: true, v: 3 },
{ id: 41, c: ['#b87333'], color: 'Copper', brand: 'Sunlu', speed: null, mat: 'PLA', type: '+', fin: 'Silk', rem: 97, tot: 1000, tare: 140, tsrc: 'community', stype: 'Sunlu — 1 kg plastic', remSrc: 'typed', kg: 19.99, cont: 'p1-ams1', label: true, v: 7 },
{ id: 42, c: ['#141414'], color: 'Black', brand: 'Elegoo', speed: 'Rapid', mat: 'PETG', type: null, fin: 'Basic', rem: 142, tot: 1000, tare: 154, tsrc: 'manufacturer', stype: 'Elegoo — 1 kg cardboard', remSrc: 'typed', kg: 11.74, cont: 'p2-ams1', label: true, v: 9 },
{ id: 43, c: ['#ece8df'], color: 'Rock White', brand: 'Overture', speed: null, mat: 'PLA', type: null, fin: 'Marble', rem: 171, tot: 1000, tare: 155, tsrc: 'community', stype: 'Overture — cardboard, PLA lines', remSrc: 'typed', kg: 17.99, cont: null, loc: 'Shelf C', label: true, v: 4 },
{ id: 44, c: ['#161616', '#c0232f'], color: 'Black Red', brand: 'TECSONAR', speed: null, mat: 'PLA', type: null, fin: 'Matte', rem: 188, tot: 1000, tare: null, tsrc: null, stype: null, remSrc: 'typed', kg: 15.99, cont: null, loc: 'Shelf C', label: false, v: 2 },
{ id: 45, c: ['#101010'], color: 'Black', brand: 'JAYO', speed: 'Rapid', mat: 'PETG', type: null, fin: 'Matte', rem: 655, tot: 1000, tare: null, tsrc: null, stype: null, remSrc: 'typed', kg: 12.72, cont: 'p1-ams1', label: true, v: 5 },
{ id: 46, c: ['#8a8f7a', '#e9e4d8'], color: 'Marble', brand: 'iSANMATE', speed: null, mat: 'ASA', type: null, fin: 'Marble', rem: 430, tot: 1000, tare: 180, tsrc: 'estimated', stype: 'Generic — 1 kg spool (assumed)', remSrc: 'weighed', kg: 25.99, cont: null, loc: 'Dry box 1', label: true, v: 6 },
{ id: 47, c: ['#1b1b1b'], color: 'Black', brand: 'Sunlu', speed: null, mat: 'PETG', type: 'CF', fin: 'Matte', rem: 812, tot: 1000, tare: 262, tsrc: 'spool', stype: 'Sunlu — 1 kg plastic', remSrc: 'weighed', weighedAt: '18 Sep 09:39', kg: 22.79, cont: 'p3-lite', label: true, v: 5 },
{ id: 48, c: ['#b8864b'], color: 'Natural Wood', brand: 'Sunlu', speed: null, mat: 'PLA', type: null, fin: 'Wood', rem: 1000, tot: 1000, tare: 35, tsrc: 'estimated', stype: 'Refill — bare cardboard core', remSrc: 'typed', kg: 16.50, cont: null, loc: 'Shelf A3', label: false, v: 1 },
{ id: 49, c: ['#a3402c'], color: 'Brick Red', brand: 'Sunlu', speed: 'High Speed', mat: 'PLA', type: null, fin: 'Marble', rem: 1000, tot: 1000, tare: 140, tsrc: 'community', stype: 'Sunlu — 1 kg plastic', remSrc: 'typed', kg: 17.50, cont: null, loc: 'Shelf A2', label: true, v: 1 },
{ id: 50, c: ['#e8453c', '#f2c230', '#2a8fd6'], color: 'Gradient Rainbow', brand: 'AMOLEN', speed: null, mat: 'PETG', type: null, fin: 'Gradient', rem: 1000, tot: 1000, tare: 180, tsrc: 'estimated', stype: 'Generic — 1 kg spool (assumed)', remSrc: 'typed', kg: 23.99, cont: null, loc: 'Shelf D', label: false, v: 1 },
{ id: 51, c: ['#1d4fa8'], color: 'Blue', brand: 'Elegoo', speed: 'Rapid', mat: 'PETG', type: null, fin: 'Basic', rem: 1000, tot: 1000, tare: 154, tsrc: 'manufacturer', stype: 'Elegoo — 1 kg cardboard', remSrc: 'typed', kg: 17.99, cont: 'p2-ams1', label: true, v: 2 },
{ id: 52, c: ['#141414'], color: 'Black', brand: 'Sunlu', speed: null, mat: 'PLA', type: '+ 2.0', fin: 'Basic', rem: 873, tot: 1000, tare: 140, tsrc: 'community', stype: 'Sunlu — 1 kg plastic', remSrc: 'typed', kg: 11.47, cont: 'p1-ams1', label: true, v: 11 },
{ id: 53, c: ['#b9bcc0'], color: 'Mist Gray', brand: 'Overture', speed: null, mat: 'PLA', type: null, fin: 'Marble', rem: 920, tot: 1000, tare: 155, tsrc: 'community', stype: 'Overture — cardboard, PLA lines', remSrc: 'typed', kg: 16.99, cont: 'p1-ams1', label: true, v: 3 },
{ id: 54, c: ['#f4f4f0'], color: 'White', brand: 'Elegoo', speed: null, mat: 'PLA', type: null, fin: 'Matte', rem: 569, tot: 1000, tare: 154, tsrc: 'manufacturer', stype: 'Elegoo — 1 kg cardboard', remSrc: 'typed', kg: 14.99, cont: 'p2-ams1', label: true, v: 6 },
{ id: 55, c: ['#e8453c', '#f2c230', '#2a8fd6'], color: 'Red Yellow Blue', brand: 'AMOLEN', speed: null, mat: 'PLA', type: null, fin: 'Matte', rem: 532, tot: 1000, tare: 180, tsrc: 'estimated', stype: 'Generic — 1 kg spool (assumed)', remSrc: 'typed', kg: 19.99, cont: 'p3-lite', label: true, v: 4 },
{ id: 56, c: ['#6e1a2a'], color: 'Transparent Wine Red', brand: 'Creality', speed: null, mat: 'PETG', type: null, fin: 'Translucent', rem: 1000, tot: 1000, tare: null, tsrc: null, stype: null, remSrc: 'typed', kg: 17.99, cont: null, loc: 'Shelf D', label: false, v: 1 }
];
var PRINTERS = [
{ id: 1, name: 'P1S - Prints Charming', model: 'P1S', ip: '10.60.1.242', serial: '01P09A••••••4821', state: 'RUNNING', connected: true, lifecycle: 'ready', stale: false, age: 2, session: 3, camera: 'snapshot', job: 'Gridfinity_bins_3x2', openPrint: 212,
containers: [{ id: 'p1-ams1', kind: 'ams', label: 'AMS 1', cap: 4 }, { id: 'p1-ext', kind: 'external', label: 'External', cap: 1 }] },
{ id: 2, name: 'H2C - Constipation Orion', model: 'H2C', ip: '10.60.1.202', serial: '31B••••••••0093', state: 'FINISH', connected: true, lifecycle: 'ready', stale: false, age: 4, session: 2, camera: 'snapshot', job: '', openPrint: null,
containers: [{ id: 'p2-ams1', kind: 'ams', label: 'AMS 1', cap: 4 }, { id: 'p2-ext', kind: 'external', label: 'External', cap: 1 }] },
{ id: 3, name: 'A1 - Jordyns Layer Slayer', model: 'A1', ip: '10.60.1.x (sample)', serial: '039••••••••7710', state: 'RUNNING', connected: false, lifecycle: 'reconnecting', stale: true, age: 366, session: 14, camera: 'snapshot', job: 'Coaster_set', openPrint: 213,
containers: [{ id: 'p3-lite', kind: 'ams_lite', label: 'AMS Lite', cap: 4 }, { id: 'p3-ext', kind: 'external', label: 'External', cap: 1 }] }
];
/* weight source: typed | sliced | recalled | unknown | null (not known yet)
* gaps: null = before counting, 0 = asked and none */
var PRINTS = [
{ id: 213, job: 'Coaster_set', key: '/coasters/plate_1.gcode', printer: 3, status: 'running', start: '2026-09-18T08:55', end: null, dur: null, gaps: 0, grams: null, wsrc: null, cost: null, spool: null, use: 'personal', open: true },
{ id: 212, job: 'Gridfinity_bins_3x2', key: '/gridfinity/bins_3x2.gcode', printer: 1, status: 'running', start: '2026-09-18T08:37', end: null, dur: null, gaps: 0, grams: null, wsrc: null, cost: null, spool: null, use: 'business' },
{ id: 211, job: 'Benchy_x4', key: '/benchy-batch/plate_1.gcode', printer: 2, status: 'finished', start: '2026-09-18T02:15', end: '2026-09-18T05:27', dur: 11520, gaps: 1, grams: 46, wsrc: 'sliced', cost: 0.54, spool: 42, use: 'business' },
{ id: 210, job: 'Sign_CubeCraft', key: '/signs/cubecraft.gcode', printer: 2, status: 'finished', start: '2026-09-17T21:48', end: '2026-09-17T23:53', dur: 7500, gaps: 0, grams: 64, wsrc: 'sliced', cost: 0.61, spool: null, use: 'business',
filaments: [{ slot: 0, spool: 54, grams: 41, hex: '#f4f4f0', cost: 0.61 }, { slot: 1, spool: null, suggested: 51, grams: 23, hex: '#1d4fa8', cost: null }] },
{ id: 209, job: 'Cable_clips', key: '/misc/cable_clips.gcode', printer: 3, status: 'unknown', start: '2026-09-17T19:30', end: '2026-09-17T21:02', dur: null, gaps: 1, grams: 12, wsrc: 'typed', cost: 0.27, spool: 47, use: 'personal' },
{ id: 208, job: 'Lid_v3', key: '/enclosure/lid_v3.gcode', printer: 1, status: 'failed', start: '2026-09-17T16:02', end: '2026-09-17T16:49', dur: 2820, gaps: 0, grams: 118, wsrc: 'typed', cost: 1.35, spool: 52, use: 'business' },
{ id: 207, job: 'Planter_small', key: '/garden/planter_small.gcode', printer: 3, status: 'finished', start: '2026-09-16T10:20', end: '2026-09-16T16:00', dur: 20400, gaps: 0, grams: 212, wsrc: 'recalled', cost: 4.24, spool: 55, use: 'personal' },
{ id: 206, job: 'Bracket_M3', key: '/brackets/m3.gcode', printer: 1, status: 'finished', start: '2026-09-16T08:05', end: '2026-09-16T09:17', dur: 4320, gaps: 0, grams: null, wsrc: null, cost: null, spool: null, use: null },
{ id: 205, job: 'Filament_clip', key: '/misc/filament_clip.gcode', printer: 1, status: 'finished', start: '2026-09-15T14:40', end: '2026-09-15T15:18', dur: 2280, gaps: 0, grams: 7, wsrc: 'sliced', cost: null, spool: null, suggested: 41, use: 'personal' },
{ id: 201, job: 'Test_cube', key: '/calibration/test_cube.gcode', printer: 1, status: 'finished', start: '2026-08-07T14:11', end: '2026-08-07T14:42', dur: 1860, gaps: null, grams: 9, wsrc: 'unknown', cost: 0.10, spool: 52, use: null, unreconciled: true }
];
var LOW = 200;
/* ── Iteration 3 additions ───────────────────────────────────────────── */
/* Lookup lists (Lists screen). `used` = spools referencing the value in the
* real 105-spool inventory where known from import/filament_review.tsv. Brand
* tares are the last-resort guess the form labels as such. */
var LOOKUPS = {
brands: [['Sunlu', 35, null], ['Elegoo', 27, null], ['Overture', 7, null], ['TECSONAR', 6, null], ['Polymaker', 4, null], ['Inland', 4, null], ['ZIRO', 3, null], ['iSANMATE', 3, null], ['Sovol', 2, null], ['JAYO', 2, null], ['GratKit', 2, null], ['Creality', 2, null], ['AMOLEN', 2, null], ['TINMORRY', 1, null], ['Kingroon', 1, null], ['Geeetech', 1, null], ['Anycubic', 1, null], ['3DimsFila', 1, null], ['Prusament', 0, null], ['eSun', 0, null], ['Hatchbox', 0, null], ['Bambu Lab', 0, null]],
materials: [['PLA', 55], ['PETG', 34], ['ASA', 10], ['TPU', 3], ['PA6', 2], ['ABS', 1]],
types: [['Standard', 0], ['CF', 3], ['GF', 4], ['+', 6], ['+ 2.0', 14], ['HF', 0], ['95A', 3]],
speeds: [['Standard', 0], ['Rapid', 18], ['High Speed', 9]],
finishes: [['Basic', 44], ['Matte', 17], ['Silk', 6], ['Sparkle', 3], ['Translucent', 4], ['Metallic', 0], ['Wood', 5], ['Marble', 12], ['Rock', 1], ['Gradient', 9], ['Glow', 0]],
spool_types: [['Generic — 1 kg spool (assumed)', 33, 180, 'estimated'], ['Sunlu — 1 kg plastic', 23, 140, 'community'], ['Elegoo — 1 kg cardboard', 20, 154, 'manufacturer'], ['Sunlu — 250 g mini', 8, 60, 'community'], ['Overture — cardboard, PLA lines', 6, 155, 'community'], ['Refill — bare cardboard core', 4, 35, 'estimated'], ['Inland — PLA Basics cardboard', 4, 143, 'community'], ['Polymaker — 0.5 kg cardboard', 3, 190, 'manufacturer'], ['Polymaker — 1 kg cardboard', 1, 140, 'manufacturer'], ['Overture — cardboard, PETG / ASA', 1, 132, 'community'], ['Bambu Lab — reusable', 0, 250, 'manufacturer'], ['Bambu Lab — cardboard', 0, 196, 'estimated'], ['Hatchbox — 1 kg', 0, 225, 'manufacturer'], ['Creality — Hyper cardboard', 0, 176, 'community']]
};
/* Holder ids as the database numbers them (used on holder labels, /c/:id). */
var HOLDER_IDS = { 'p1-ams1': 1, 'p1-ext': 2, 'p2-ams1': 3, 'p2-ext': 4, 'p3-lite': 5, 'p3-ext': 6 };
/* Access (humans come from Authentik; Extrudex shows its local projection). */
var PEOPLE = [
{ id: 1, name: 'Joshua King', email: 'owner@cubecraft (sample)', role: 'admin', lastSeen: '2026-09-18T09:40', sessions: [{ created: '2026-09-18T07:02', lastSeen: '2026-09-18T09:40', idleExp: '2026-09-18T17:40', maxExp: '2026-09-25T07:02', revoked: null, you: true }, { created: '2026-09-15T20:11', lastSeen: '2026-09-17T22:03', idleExp: '2026-09-18T06:03', maxExp: '2026-09-22T20:11', revoked: null }] },
{ id: 2, name: 'Jordyn', email: 'jordyn@cubecraft (sample)', role: 'operator', lastSeen: '2026-09-17T19:28', sessions: [{ created: '2026-09-17T18:50', lastSeen: '2026-09-17T19:28', idleExp: '2026-09-18T03:28', maxExp: '2026-09-24T18:50', revoked: null }] },
{ id: 3, name: 'Guest tablet', email: null, role: 'reader', lastSeen: '2026-09-09T12:00', sessions: [] }
];
var MACHINES = [
{ id: 10, name: 'hermes-gateway', role: 'operator', tokens: [{ id: 21, name: 'gateway 2026-09', created: '2026-09-01T10:00', lastUsed: '2026-09-18T09:39', revoked: null }, { id: 17, name: 'gateway 2026-08', created: '2026-08-03T10:00', lastUsed: '2026-08-31T23:58', revoked: '2026-09-01T10:02' }] },
{ id: 11, name: 'uptime-kuma', role: 'reader', tokens: [{ id: 22, name: 'health probe', created: '2026-09-05T14:30', lastUsed: '2026-09-18T09:41', revoked: null }] }
];
var AUDIT = [
{ id: 9031, who: 'Joshua King', action: 'spool.weighed', type: 'spool', rid: 47, ctx: '860 g → 812 g · tare 262 g (spool)', at: '2026-09-18T09:39' },
{ id: 9030, who: 'hermes-gateway', action: 'print.spool_set', type: 'print', rid: 211, ctx: 'spool #42 · 46 g deducted at $11.74/kg', at: '2026-09-18T05:28' },
{ id: 9029, who: 'Jordyn', action: 'spool.moved', type: 'spool', rid: 55, ctx: 'Shelf D → A1 · AMS Lite', at: '2026-09-17T19:26' },
{ id: 9028, who: 'Jordyn', action: 'print.use_type_set', type: 'print', rid: 209, ctx: 'personal', at: '2026-09-17T19:25' },
{ id: 9027, who: 'Joshua King', action: 'lookup.updated', type: 'spool_type', rid: 4, ctx: 'Sunlu — 250 g mini · tare 60 g · community', at: '2026-09-17T08:12' },
{ id: 9026, who: 'Joshua King', action: 'printer.updated', type: 'printer', rid: 3, ctx: 'ip changed · access code unchanged', at: '2026-09-16T21:40' },
{ id: 9025, who: 'Joshua King', action: 'session.revoked', type: 'principal', rid: 3, ctx: '1 local session', at: '2026-09-09T12:05' }
];
var WEBHOOK = { enabled: true, schedule: 'Mondays 08:00 America/New_York', threshold: 200, target: 'configured (URL kept in a root-only file, never shown)',
events: [{ period: '2026-W38', observed: '2026-09-14T08:00', state: 'delivered', attempts: 1, spools: 4, delivered: '2026-09-14T08:00' }, { period: '2026-W37', observed: '2026-09-07T08:00', state: 'delivered', attempts: 3, spools: 3, delivered: '2026-09-07T08:21', lastError: 'HTTP 502 from receiver (retried)' }, { period: '2026-W36', observed: '2026-08-31T08:00', state: 'no_low', attempts: 0, spools: 0 }] };
/* Iteration-2 shared behaviour: shell, navigation badges, command palette,
* drawers (spool / print / load), toasts, freshness and demo states.
* Plain browser JS, no dependencies, works offline. */
(function () {
'use strict';
/* ── helpers ─────────────────────────────────────────────── */
var $ = function (s, r) { return (r || document).querySelector(s); };
var $$ = function (s, r) { return Array.prototype.slice.call((r || document).querySelectorAll(s)); };
function esc(s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); }
function g(n) { return n == null ? '—' : Math.round(n).toLocaleString('en-US') + ' g'; }
function kg(n) { return (n / 1000).toFixed(2) + ' kg'; }
function usd(n) { return n == null ? '—' : '$' + n.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }
function dur(s) { if (s == null) return '—'; if (s < 60) return '<1m'; var h = Math.floor(s / 3600), m = Math.floor(s % 3600 / 60); return h ? h + 'h ' + String(m).padStart(2, '0') + 'm' : m + 'm'; }
function when(iso) {
if (!iso) return '—';
var d = new Date(iso), t = d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' });
var days = Math.round((new Date(NOW.toDateString()) - new Date(d.toDateString())) / 864e5);
if (days === 0) return 'Today ' + t;
if (days === 1) return 'Yesterday ' + t;
return d.getDate() + ' ' + d.toLocaleString('en-GB', { month: 'short' }) + ' ' + t;
}
function ago(sec) { if (sec < 60) return sec + 's ago'; var m = Math.floor(sec / 60); if (m < 60) return m + 'm ago'; var h = Math.floor(m / 60); return h < 24 ? h + 'h ago' : Math.floor(h / 24) + 'd ago'; }
function since(iso) { return Math.max(0, Math.round((NOW - new Date(iso)) / 1000)); }
var byId = function (arr, id) { for (var i = 0; i < arr.length; i++) if (arr[i].id === id) return arr[i]; return null; };
function spool(id) { return byId(SPOOLS, id); }
function printer(id) { return byId(PRINTERS, id); }
function print(id) { return byId(PRINTS, id); }
function container(cid) {
for (var i = 0; i < PRINTERS.length; i++) for (var j = 0; j < PRINTERS[i].containers.length; j++)
if (PRINTERS[i].containers[j].id === cid) return { printer: PRINTERS[i], c: PRINTERS[i].containers[j] };
return null;
}
function contents(cid) { return SPOOLS.filter(function (s) { return s.cont === cid; }); }
function fullName(s) { return [s.brand, s.speed, s.mat, s.type, s.fin].filter(Boolean).join(' '); }
function short(s) { return s.brand + ' ' + s.color; }
function where(s) {
if (!s.cont) return { loaded: false, text: s.loc || 'Storage', short: s.loc || 'Storage' };
var c = container(s.cont);
return { loaded: true, text: c.printer.name + ' · ' + c.c.label, short: c.printer.model + ' · ' + c.c.label, printer: c.printer };
}
/* Unknown, or an estimated figure nobody weighed: the weigh-in would rest on a guess. */
function unverified(s) { return s.tare == null || s.tsrc === 'estimated'; }
function gross(s) { return s.tare == null ? null : s.tare + s.rem; }
function value(s) { return s.rem / 1000 * s.kg; }
function low(s) { return s.rem < LOW; }
function sw(colors, cls) { return '<span class="swatch ' + (cls || '') + '" aria-hidden="true">' + colors.map(function (h) { return '<i style="background:' + h + '"></i>'; }).join('') + '</span>'; }
function meter(s) {
var pct = Math.max(0, Math.min(100, s.rem / s.tot * 100)), tick = Math.min(100, LOW / s.tot * 100);
return '<div class="meter' + (low(s) ? ' is-low' : '') + '" role="meter" aria-valuemin="0" aria-valuemax="' + s.tot + '" aria-valuenow="' + s.rem + '" aria-label="' + esc(s.color) + ' remaining"><span style="width:' + pct + '%"></span><i class="tick" style="left:' + tick + '%" title="200 g low-stock line"></i></div>';
}
/* provenance: quiet icon + words */
var TSRC = { spool: ['⚖', 'weighed bare', ''], manufacturer: ['◆', 'manufacturer', ''], community: ['◇', 'community', ''], estimated: ['≈', 'estimated', 'warn'] };
function tareProv(s) {
if (s.tare == null) return '<span class="prov warn"><i>?</i>empty spool weight unknown</span>';
var t = TSRC[s.tsrc]; return '<span class="prov ' + t[2] + '" title="' + esc(s.tsrc === 'spool' ? 'This reel was weighed empty' : 'From spool type: ' + s.stype) + '"><i>' + t[0] + '</i>' + t[1] + '</span>';
}
function remProv(s) { return s.remSrc === 'weighed' ? '<span class="prov"><i>⚖</i>weighed' + (s.weighedAt ? ' ' + esc(s.weighedAt) : '') + '</span>' : '<span class="prov"><i>✎</i>typed</span>'; }
var WSRC = { typed: ['✎', 'typed', '', 'A measurement someone entered. Survives an identity correction.'], sliced: ['▦', 'sliced', 'info', "Read from this run's 3MF over FTPS."], recalled: ['⎘', 'recalled', 'info', 'Copied from the weight remembered for this gcode path. No longer written.'], unknown: ['?', 'source unknown', 'warn', 'Written before the source was recorded. Neither correction path will move it.'] };
function weightProv(p) { if (!p.wsrc) return ''; var w = WSRC[p.wsrc]; return '<span class="prov ' + w[2] + '" title="' + esc(w[3]) + '"><i>' + w[0] + '</i>' + w[1] + '</span>'; }
function durCell(p) {
if (p.status === 'running') return '<span class="num">' + dur(since(p.start)) + '</span><span class="sub">so far</span>';
if (p.status === 'unknown') return '<span class="muted" title="Nobody saw this print end. The only measurable figure is the outage, which is not how long anything printed.">no duration</span><span class="sub">end not seen</span>';
if (p.gaps) return '<span class="num strong" style="color:var(--status-warning)" title="The connection dropped ' + (p.gaps === 1 ? 'once' : p.gaps + ' times') + ' during this print. That time is inside the figure and nobody watched it, so it is an upper bound.">≤ ' + dur(p.dur) + '</span><span class="sub prov warn">upper bound · ' + p.gaps + ' gap' + (p.gaps > 1 ? 's' : '') + '</span>';
if (p.gaps == null) return '<span class="num">' + dur(p.dur) + '</span><span class="sub" title="Predates gap counting: nobody asked whether the connection dropped.">gaps not counted</span>';
return '<span class="num">' + dur(p.dur) + '</span>';
}
var PST = { running: ['run', 'Running'], finished: ['ok', 'Finished'], failed: ['err', 'Failed'], unknown: ['warn', 'Unknown'] };
function printSt(p) { var s = PST[p.status]; return '<span class="st ' + s[0] + '">' + s[1] + '</span>'; }
function printerSt(pr) {
if (!pr.connected) return '<span class="st warn">' + (pr.lifecycle === 'reconnecting' ? 'Reconnecting' : 'Offline') + '</span>';
if (pr.state === 'RUNNING') return '<span class="st run">Printing</span>';
if (pr.state === 'PAUSE') return '<span class="st warn">Paused</span>';
if (pr.state === 'FAILED') return '<span class="st err">Failed</span>';
return '<span class="st idle">Idle</span>';
}
/* what a print still needs; empty while running */
function needs(p) {
if (p.status === 'running') return [];
var n = [];
if (p.grams == null) n.push({ k: 'weight', t: 'filament weight' });
if (p.filaments) p.filaments.forEach(function (f) { if (f.spool == null) n.push({ k: 'spool', t: 'spool for color ' + (f.slot + 1), f: f }); });
else if (p.spool == null) n.push({ k: 'spool', t: 'spool' });
return n;
}
function printsNeeding() { return PRINTS.filter(function (p) { return needs(p).length && !p.archived; }); }
function spoolLinks(p) {
if (p.filaments) return p.filaments.map(function (f) { var s = f.spool && spool(f.spool); return s ? '<a href="#spool=' + s.id + '" data-spool="' + s.id + '">' + sw(s.c, 'swatch-sm') + ' ' + esc(short(s)) + '</a>' : '<span class="prov warn"><i>!</i>color ' + (f.slot + 1) + ' unattributed</span>'; }).join('<br>');
var s = p.spool && spool(p.spool);
return s ? '<a href="#spool=' + s.id + '" data-spool="' + s.id + '" class="nowrap">' + sw(s.c, 'swatch-sm') + ' ' + esc(short(s)) + '</a>' : (p.status === 'running' ? '<span class="muted">—</span>' : '<span class="prov warn"><i>!</i>no spool</span>');
}
/* ── shell ───────────────────────────────────────────────── */
var ICON = {
dashboard: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="3" y="3" width="7" height="9" rx="2"/><rect x="14" y="3" width="7" height="5" rx="2"/><rect x="14" y="12" width="7" height="9" rx="2"/><rect x="3" y="16" width="7" height="5" rx="2"/></svg>',
filament: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="3"/><path d="M12 3v6M12 15v6"/></svg>',
prints: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M5 20h14M7 16l3-9h4l3 9M9 12h6"/></svg>',
printers: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="4" y="3" width="16" height="18" rx="2"/><path d="M8 17h8M9 7h6v5H9z"/></svg>',
lists: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11M4 6h.01M4 12h.01M4 18h.01"/></svg>',
labels: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 12V4h8l10 10-8 8z"/><circle cx="7.5" cy="7.5" r="1.5"/></svg>',
access: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="9" cy="8" r="4"/><path d="M2 21a7 7 0 0 1 14 0M17 11l2 2 4-4"/></svg>',
system: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M4 6h16M4 12h10M4 18h7"/><circle cx="18" cy="16" r="3"/></svg>',
more: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/></svg>',
search: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-4-4"/></svg>',
sun: '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>'
};
var MANAGE = [['lists', 'Lists', '05-lists.html', 0], ['labels', 'Labels', '06-labels.html', 0], ['access', 'Access', '07-access.html', 1], ['system', 'System', '08-system.html', 1]];
var PAGES = [['dashboard', 'Dashboard', '01-dashboard.html'], ['filament', 'Filament', '02-filament.html'], ['prints', 'Prints', '03-prints.html'], ['printers', 'Printers', '04-printers.html']];
function badges() {
var need = printsNeeding().length, down = PRINTERS.filter(function (p) { return !p.connected; }).length;
var unv = SPOOLS.filter(unverified), unk = unv.filter(function (s) { return s.tare == null; }).length;
return {
filament: unv.length ? '<span class="count count-warn" title="' + unv.length + ' spools with an unverified empty spool weight: ' + unk + ' unknown, ' + (unv.length - unk) + ' estimated">' + unv.length + '</span>' : '',
prints: need ? '<span class="count count-warn" title="' + need + ' prints need a spool or weight">' + need + '</span>' : '',
printers: down ? '<span class="count count-err" title="' + down + ' printer not connected">' + down + '</span>' : ''
};
}
function shell(page) {
var b = badges();
var nav = PAGES.map(function (p) { return '<a href="' + p[2] + '"' + (p[0] === page ? ' aria-current="page"' : '') + '>' + ICON[p[0]] + '<span>' + p[1] + '</span>' + (b[p[0]] || '') + '</a>'; }).join('');
var unl = SPOOLS.filter(function (s) { return !s.label; }).length;
var rail = '<nav class="rail nm-raised" aria-label="Main">' +
'<a class="wordmark" href="01-dashboard.html" style="text-decoration:none;color:inherit"><span class="wordmark-mark" aria-hidden="true">X</span>Extrudex</a>' +
'<div class="nav nav-group">' + nav + '</div>' +
'<div class="nav nav-group"><span class="nav-label">Manage</span>' +
MANAGE.map(function (m) { return '<a href="' + m[2] + '"' + (m[0] === page ? ' aria-current="page"' : '') + '>' + ICON[m[0]] + '<span>' + m[1] + '</span>' + (m[0] === 'labels' ? '<span class="count" style="color:var(--text-secondary)" title="' + unl + ' spools without a printed label">' + unl + '</span>' : m[3] ? '<span class="sub" style="margin-left:auto">admin</span>' : '') + '</a>'; }).join('') + '</div>' +
'<div class="rail-foot"><div class="seg" role="group" aria-label="Color theme"><button type="button" data-set-theme="light">Light</button><button type="button" data-set-theme="dark">Dark</button></div>' +
'<span class="small muted">Signed in · operator</span></div></nav>';
var inManage = MANAGE.some(function (m) { return m[0] === page; });
var tabbar = '<nav class="tabbar nm-raised" aria-label="Main">' + PAGES.map(function (p) { return '<a href="' + p[2] + '"' + (p[0] === page ? ' aria-current="page"' : '') + '>' + ICON[p[0]] + (b[p[0]] || '') + '<span>' + p[1] + '</span></a>'; }).join('') +
'<a href="#" data-menu="moremenu" aria-haspopup="menu" aria-expanded="false"' + (inManage ? ' aria-current="page"' : '') + '>' + ICON.more + '<span>More</span></a></nav>' +
'<div class="menu more-sheet nm-dialog" id="moremenu" role="menu" aria-label="More">' + MANAGE.map(function (m) { return '<a role="menuitem" href="' + m[2] + '">' + ICON[m[0]] + ' ' + m[1] + (m[3] ? '<span class="hint">admin</span>' : '') + '</a>'; }).join('') + '<hr><button role="menuitem" type="button" data-toggle-theme>' + ICON.sun + ' Switch light / dark</button></div>';
var top = '<div class="topbar"><button class="search-trigger" type="button" data-palette>' + ICON.search + '<span style="flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis"><span class="long">Search spools, prints, printers…</span><span class="short">Search…</span></span><span class="kbd long">⌘K</span></button>' +
'<span class="fresh" id="fresh" role="status"><span class="dot" aria-hidden="true"></span><span id="fresh-t">Live · updated 3s ago</span></span>' +
'<button class="btn btn-icon btn-sm" type="button" data-toggle-theme aria-label="Switch color theme">' + ICON.sun + '</button></div>';
var mock = '<div class="mock"><button type="button" data-menu="mockmenu" aria-expanded="false">Mockup<span class="long"> · v3 iteration 3</span></button><div class="menu" id="mockmenu" role="dialog" aria-label="About this mockup">' +
'<p><b>Sample data</b>, based on the real inventory. Nothing is wired to the API.</p>' +
'<p><span class="prov info"><i>◈</i>feature</span> fields exist only on the printer-connections branch. <span class="prov warn"><i>⚠</i>API gap</span> means stored but not served.</p><hr>' +
'<button type="button" data-demo="loading">Replay first load (skeletons)</button>' +
'<button type="button" data-demo="offline">Simulate polling failure</button>' +
'<button type="button" data-demo="online">Back to live</button><hr>' +
'<a href="index.html">Flow map of all screens →</a></div></div>';
var drawer = '<div class="drawer-scrim" data-close-drawer></div><aside class="drawer nm-dialog" id="drawer" role="dialog" aria-modal="true" aria-labelledby="drawer-title" hidden></aside>';
var pal = '<div class="pal-scrim" id="pal" role="presentation"><div class="pal nm-dialog" role="dialog" aria-modal="true" aria-label="Search and commands"><div class="pal-input">' + ICON.search +
'<input id="pal-q" role="combobox" aria-expanded="true" aria-controls="pal-list" aria-autocomplete="list" placeholder="Type a spool, #id, job, printer or action…" autocomplete="off"><span class="kbd">esc</span></div>' +
'<div class="pal-list" id="pal-list" role="listbox"></div><div class="pal-foot"><span><span class="kbd">↑</span> <span class="kbd">↓</span> move</span><span><span class="kbd">↵</span> open</span><span><span class="kbd">/</span> or <span class="kbd">⌘K</span> anywhere</span></div></div></div>';
return { rail: rail, tabbar: tabbar, top: top, rest: mock + drawer + pal + '<div class="toasts" id="toasts" aria-live="polite"></div>' };
}
/* ── theme ───────────────────────────────────────────────── */
function setTheme(v) {
document.documentElement.setAttribute('data-theme', v);
$$('[data-set-theme]').forEach(function (b) { b.setAttribute('aria-pressed', String(b.getAttribute('data-set-theme') === v)); });
try { localStorage.setItem('extrudex-v3-theme', v); } catch (e) {}
}
/* ── toasts ──────────────────────────────────────────────── */
function updateBadges() {
var b = badges();
$$('.nav a, .tabbar a').forEach(function (a) {
var key = { '02-filament.html': 'filament', '03-prints.html': 'prints', '04-printers.html': 'printers' }[a.getAttribute('href')]; if (!key) return;
var old = a.querySelector('.count'); if (old) old.parentNode.removeChild(old);
if (b[key]) a.querySelector('span').insertAdjacentHTML(a.closest('.tabbar') ? 'beforebegin' : 'afterend', b[key]);
});
}
function toast(html, kind) {
setTimeout(updateBadges, 0);
var t = document.createElement('div'); t.className = 'toast ' + (kind || ''); t.setAttribute('role', 'status');
t.innerHTML = '<span>' + html + '</span><button class="btn btn-sm btn-icon" type="button" aria-label="Dismiss">✕</button>';
$('#toasts').appendChild(t);
var kill = function () { if (t.parentNode) t.parentNode.removeChild(t); };
t.querySelector('button').onclick = kill; setTimeout(kill, 6000);
}
/* ── drawer ──────────────────────────────────────────────── */
var D = { kind: null, id: null, tab: 'overview', state: 'normal', list: null, lastFocus: null, dirty: false };
function openDrawer(kind, id, tab, push) {
D.kind = kind; D.id = id; D.tab = tab || 'overview'; D.state = 'normal'; D.dirty = false;
if (!document.body.classList.contains('drawer-open')) D.lastFocus = document.activeElement;
renderDrawer();
var el = $('#drawer'); el.hidden = false;
requestAnimationFrame(function () { document.body.classList.add('drawer-open'); var f = el.querySelector('[autofocus]') || el.querySelector('h2'); if (f) { f.setAttribute('tabindex', f.tagName === 'H2' ? '-1' : f.getAttribute('tabindex')); f.focus(); } });
var h = '#' + kind + '=' + id + (D.tab !== 'overview' ? '&tab=' + D.tab : '');
if (push !== false && location.hash !== h) history.pushState({ d: 1 }, '', h);
$$('[data-row-spool],[data-row-print]').forEach(function (r) { r.classList.toggle('is-selected', (kind === 'spool' && +r.getAttribute('data-row-spool') === id) || (kind === 'print' && +r.getAttribute('data-row-print') === id)); });
}
function closeDrawer(push) {
if (D.dirty && !confirmDiscard()) return;
document.body.classList.remove('drawer-open'); D.kind = null; D.session = false; D.brand = null;
setTimeout(function () { if (!D.kind) $('#drawer').hidden = true; }, 240);
if (push !== false && location.hash) history.pushState({}, '', location.pathname + location.search);
$$('.is-selected').forEach(function (r) { r.classList.remove('is-selected'); });
if (D.lastFocus && D.lastFocus.focus) D.lastFocus.focus();
}
function confirmDiscard() {
var bar = $('#discard-bar'); if (bar) { bar.hidden = false; bar.querySelector('button').focus(); return false; }
return true;
}
function renderDrawer() {
var el = $('#drawer');
if (D.kind === 'spool') el.innerHTML = spoolDrawer(spool(D.id));
else if (D.kind === 'new') el.innerHTML = editDrawer(null);
else if (D.kind === 'print') el.innerHTML = printDrawer(print(D.id));
else if (D.kind === 'load') el.innerHTML = loadDrawer(D.id);
else if (D.kind === 'pedit') el.innerHTML = peditDrawer(D.id);
else if (D.kind === 'holders') el.innerHTML = holdersDrawer(D.id);
else if (D.kind === 'premove') el.innerHTML = premoveDrawer(D.id);
if (window.PAGE && PAGE.onDrawer) PAGE.onDrawer();
}
function head(icon, title, sub, extra) {
var list = D.list || [], i = list.indexOf(D.id);
var nav = (D.kind === 'spool' && i >= 0 && list.length > 1) ? '<div class="drawer-nav"><button class="btn btn-sm btn-icon" type="button" data-step="-1" aria-label="Previous spool in list" ' + (i === 0 ? 'disabled' : '') + '>↑</button><button class="btn btn-sm btn-icon" type="button" data-step="1" aria-label="Next spool in list" ' + (i === list.length - 1 ? 'disabled' : '') + '>↓</button></div>' : '';
return '<div class="drawer-head">' + icon + '<div style="flex:1;min-width:0"><h2 id="drawer-title">' + title + '</h2><span class="sub">' + sub + '</span>' + (extra || '') + '</div>' + nav + '<button class="btn btn-sm btn-icon" type="button" data-close-drawer aria-label="Close panel (Esc)">✕</button></div>';
}
function tabs(list) {
return '<div class="drawer-tabs"><div class="tabs" role="tablist" aria-label="Spool panel">' + list.map(function (t) { return '<button type="button" role="tab" data-tab="' + t[0] + '" aria-selected="' + (D.tab === t[0]) + '">' + t[1] + '</button>'; }).join('') + '</div></div>';
}
function spoolDrawer(s) {
var w = where(s);
var h = head(sw(s.c, '" style="width:44px;height:44px'), esc(s.color) + ' <span class="muted" style="font-weight:400">#' + s.id + '</span>', esc(fullName(s)) + ' · ' + esc(w.text));
var t = tabs([['overview', 'Overview'], ['weigh', 'Weigh'], ['move', w.loaded ? 'Move' : 'Load / move'], ['edit', 'Edit']]);
var body = '', foot = '';
if (D.tab === 'overview') {
var used = PRINTS.filter(function (p) { return p.spool === s.id || (p.filaments || []).some(function (f) { return f.spool === s.id; }); });
var gr = gross(s);
body = '<div class="nm-inset panel"><div class="row" style="align-items:baseline"><span style="font-size:34px;font-weight:800;line-height:1" class="num' + (low(s) ? '" style="color:var(--status-warning)' : '') + '">' + Math.round(s.rem).toLocaleString('en-US') + '<span style="font-size:15px"> g</span></span><span class="muted">of ' + g(s.tot) + ' net</span><span class="spacer"></span>' + remProv(s) + '</div>' +
'<div style="margin-top:12px">' + meter(s) + '</div>' + (low(s) ? '<p class="small" style="margin:10px 0 0;color:var(--status-warning)"><b>⚠ Below the 200 g line.</b> Reorder or finish it on a small job.</p>' : '') + '</div>' +
'<div class="panel nm-raised-sm"><h3>On the scale</h3>' + (gr == null
? '<p class="small" style="margin:0">Gross is <b>unknown</b> because no empty spool weight is known. It is never treated as 0.</p><div class="row" style="margin-top:12px"><button class="btn btn-sm" type="button" data-tab="weigh">Set empty spool weight</button></div>'
: '<dl class="kv"><dt>Empty spool</dt><dd>' + g(s.tare) + ' ' + tareProv(s) + '</dd><dt>+ Filament (net)</dt><dd>' + g(s.rem) + '</dd><dt class="strong" style="color:var(--text-primary)">= Gross, on a scale</dt><dd class="strong">' + g(gr) + '</dd></dl>') + '</div>' +
'<dl class="kv"><dt>Location</dt><dd>' + (w.loaded ? '<a href="04-printers.html#printer=' + w.printer.id + '">' + esc(w.text) + '</a>' : esc(w.text)) + ' · <button class="btn btn-sm" type="button" data-tab="move" style="min-height:26px;padding:2px 8px">Move</button></dd>' +
'<dt>Value left</dt><dd>' + usd(value(s)) + ' <span class="sub" style="display:inline">at ' + usd(s.kg) + '/kg</span></dd>' +
'<dt>Spool type</dt><dd>' + (s.stype ? esc(s.stype) : '<span class="muted">none chosen</span>') + '</dd>' +
'<dt>Label</dt><dd>' + (s.label ? 'printed' : '<span class="prov warn"><i>!</i>not printed</span> <button class="btn btn-sm" type="button" data-fake="Label PDF generated for #' + s.id + '" style="min-height:26px;padding:2px 8px">Print label</button>') + '</dd>' +
'<dt>Record</dt><dd class="muted">version ' + s.v + '</dd></dl>' +
'<div><h3 class="section" style="margin-bottom:8px">Prints from this spool <span class="muted">· ' + used.length + '</span></h3>' + (used.length ? '<div class="stack" style="gap:6px">' + used.map(function (p) { var f = (p.filaments || []).filter(function (f) { return f.spool === s.id; })[0]; return '<a class="row nm-raised-sm" style="padding:8px 12px;text-decoration:none;color:inherit;gap:10px" href="#print=' + p.id + '" data-print="' + p.id + '">' + printSt(p) + '<span class="strong" style="flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis">' + esc(p.job) + '</span><span class="num">' + g(f ? f.grams : p.grams) + '</span><span class="sub" style="display:inline">' + when(p.start) + '</span></a>'; }).join('') + '</div>' : '<p class="small muted" style="margin:0">No prints drew from this spool yet.</p>') + '</div>' +
'<p class="small muted" style="margin:0"><span class="prov warn"><i>⚠</i>API gap</span> Location history is stored in <code>spool_location_event</code> but there is no endpoint to read it.</p>';
foot = '<button class="btn btn-danger btn-sm" type="button" data-delete="' + s.id + '" style="margin-right:auto">Delete…</button><button class="btn" type="button" data-tab="edit">Edit</button><button class="btn btn-primary" type="button" data-tab="weigh" ' + (s.tare == null ? 'title="Needs an empty spool weight first"' : '') + '>Weigh</button>';
}
if (D.tab === 'weigh') {
if (s.tare == null) {
body = '<div class="banner"><b>?</b><span>This spool has <b>no empty spool weight</b>, so a scale reading can\'t be turned into filament. Set one first. It is never assumed to be 0.</span></div>' +
'<label class="field stack" style="gap:6px"><span class="strong small">Pick a spool type</span><select class="select" autofocus><option>Choose…</option><option>Generic — 1 kg spool (assumed) · 180 g · estimated</option><option>Creality — Hyper cardboard · 176 g · community</option><option>Creality — legacy plastic · 138 g · community</option></select><span class="sub">Fastest. The figure\'s trust level is shown next to it.</span></label>' +
'<div class="row"><hr style="flex:1;border:0;border-top:1px solid var(--border-hairline)"><span class="sub">or, more accurate</span><hr style="flex:1;border:0;border-top:1px solid var(--border-hairline)"></div>' +
'<label class="field stack" style="gap:6px"><span class="strong small">Weigh the empty spool</span><input class="input num" inputmode="numeric" placeholder="e.g. 210 g"><span class="sub">Only possible once the spool is used up, or from an identical empty.</span></label>';
foot = '<button class="btn" type="button" data-tab="overview">Cancel</button><button class="btn btn-primary" type="button" data-fake="Empty spool weight saved for #' + s.id + '. Weigh-in unlocked.">Save empty spool weight</button>';
} else {
var wl = where(s), li = D.list ? D.list.indexOf(s.id) : -1;
body = (D.session && li >= 0 ? '<div class="row small" style="gap:10px"><span class="st run">Weigh session</span><span class="muted">spool ' + (li + 1) + ' of ' + D.list.length + ' · lightest first</span></div>' : '') +
'<div class="findit"><span class="sub">Find it</span><b>' + esc(wl.text) + '</b>' + sw(s.c, 'swatch-sm') + '<span class="muted small">' + esc(s.color) + ' · #' + s.id + '</span></div>' +
'<div class="panel nm-inset"><label class="stack" style="gap:8px"><span class="strong">Whole spool on the scale</span><input class="input num" id="scale" inputmode="numeric" autofocus placeholder="full reads ' + g(s.tare + s.tot) + '" style="font-size:22px;min-height:56px"><span class="sub">Remaining = reading − ' + g(s.tare) + ' empty spool (' + tareProv(s) + ')</span></label></div>' +
'<div class="panel nm-raised-sm" id="weigh-out" aria-live="polite"><h3>Result</h3><div class="row"><span class="muted">Now</span><b class="num">' + g(s.rem) + '</b><span class="muted">→</span><b class="num" id="w-after">—</b><span class="spacer"></span><span id="w-diff" class="num"></span></div><p class="small muted" id="w-note" style="margin:8px 0 0">Type the reading and the result appears here before you save.</p></div>';
foot = '<button class="btn" type="button" data-tab="overview">Cancel</button><button class="btn btn-primary" type="button" id="w-save" disabled>Save weigh-in</button>' + (D.list && D.list.indexOf(s.id) < D.list.length - 1 ? '<button class="btn" type="button" id="w-next" disabled>Save & weigh next ↓</button>' : '');
}
}
if (D.tab === 'move') {
var dests = PRINTERS.map(function (pr) {
return '<div class="stack" style="gap:8px"><div class="row"><b class="small">' + esc(pr.name) + '</b>' + (pr.connected ? '' : '<span class="prov warn"><i>⚡</i>disconnected (loading still recorded)</span>') + '</div><div class="row" style="gap:8px;align-items:stretch">' +
pr.containers.map(function (c) { var n = contents(c.id).length, full = n >= c.cap && s.cont !== c.id, here = s.cont === c.id; return '<button type="button" class="slot" style="min-height:64px;flex:1" data-dest="' + c.id + '" ' + (full ? 'disabled title="Full: unload a spool first"' : '') + ' aria-pressed="' + here + '"><span class="sn">' + esc(c.label) + '</span><span class="g">' + n + ' / ' + c.cap + (here ? ' · here now' : full ? ' · full' : '') + '</span></button>'; }).join('') + '</div></div>';
}).join('');
body = '<p class="small muted" style="margin:0">Where is the spool going? Full holders are disabled. Extrudex records which holder a spool is in, not its tray position.</p>' +
'<div class="stack" style="gap:8px"><b class="small">Storage</b><div class="row" style="gap:8px;align-items:stretch"><button type="button" class="slot" style="min-height:64px;flex:1" data-dest="storage" aria-pressed="' + !s.cont + '"><span class="sn">Shelf / storage</span><span class="g">' + (s.cont ? 'unload' : 'here now') + '</span></button></div>' +
'<label class="stack" style="gap:6px"><span class="sub">Where in storage (optional)</span><input class="input" value="' + esc(s.loc || '') + '" placeholder="Shelf A2, Dry box 1…"></label></div>' + dests;
foot = '<button class="btn" type="button" data-tab="overview">Cancel</button><button class="btn btn-primary" type="button" id="m-save" disabled>Move spool</button>';
}
if (D.tab === 'edit') { return editDrawer(s); }
return h + t + '<div class="drawer-body">' + body + '</div><div class="drawer-foot">' + foot + '</div>';
}
function editDrawer(s) {
var isNew = !s; s = s || { id: null, c: ['#888888'], color: '', brand: 'Sunlu', speed: null, mat: 'PLA', type: null, fin: 'Basic', rem: 1000, tot: 1000, tare: 140, tsrc: 'community', stype: 'Sunlu — 1 kg plastic', kg: 0, loc: '', v: null };
var st = D.state;
var h = isNew ? head('<span class="swatch" style="width:44px;height:44px"><i style="background:#888"></i></span>', 'Add spool', 'New spools carry no version') : head(sw(s.c, '" style="width:44px;height:44px'), 'Edit ' + esc(s.color) + ' <span class="muted" style="font-weight:400">#' + s.id + '</span>', 'Opened 09:32 at version ' + (st === 'conflict' ? s.v - 1 : s.v));
var t = isNew ? '' : tabs([['overview', 'Overview'], ['weigh', 'Weigh'], ['move', where(s).loaded ? 'Move' : 'Load / move'], ['edit', 'Edit']]);
function sel(label, val, req, opts) { return '<label class="stack" style="gap:6px"><span class="small strong">' + label + ' ' + (req ? '<span class="sub" style="display:inline;color:var(--text-accent)">required</span>' : '<span class="sub" style="display:inline">optional</span>') + '</span><select class="select"><option>' + (val || 'None') + '</option>' + (opts || '') + '</select></label>'; }
var demo = '<div class="row small" style="gap:8px"><span class="muted">Demo state</span><div class="tabs" role="group" aria-label="Demo state">' + [['normal', 'Normal'], ['errors', '400 errors'], ['conflict', '409 conflict']].map(function (x) { return '<button type="button" data-state="' + x[0] + '" aria-selected="' + (st === x[0]) + '">' + x[1] + '</button>'; }).join('') + '</div></div>';
var conflict = st === 'conflict' ? '<div class="nm-inset" role="alert" style="padding:16px;border:2px solid var(--status-warning);background:var(--wash-warning);border-radius:var(--radius-lg)"><b style="color:var(--status-warning)">⚠ This spool changed since you opened it. Nothing was saved.</b><p class="small" style="margin:8px 0">Someone weighed it at 09:39 (version ' + (s.v - 1) + ' → ' + s.v + '). Saving would have put the old remaining weight back.</p>' +
'<table class="tbl" style="font-size:12px"><thead><tr><th>Field</th><th class="r">You opened</th><th class="r">Now</th><th class="r">Your edit</th></tr></thead><tbody><tr><td>Remaining</td><td class="r">860 g</td><td class="r strong" style="color:var(--status-warning)">' + g(s.rem) + ' ⚖</td><td class="r muted">—</td></tr><tr><td>Location</td><td class="r">Shelf A3</td><td class="r">Shelf A3</td><td class="r strong accent">' + esc(where(s).short) + '</td></tr></tbody></table>' +
'<div class="row" style="margin-top:12px"><button class="btn btn-primary btn-sm" type="button" data-fake="Reloaded version ' + s.v + ' and reapplied your location change. Review, then save.">Reload & reapply my change</button><button class="btn btn-sm" type="button" data-state="normal">Reload, discard mine</button></div></div>' : '';
var errsum = st === 'errors' ? '<div role="alert" style="padding:14px 16px;border:2px solid var(--status-error);background:var(--wash-error);border-radius:var(--radius-lg)"><b style="color:var(--status-error)">⚠ 2 fields need fixing. Nothing was saved.</b><ul class="small" style="margin:6px 0 0;padding-left:18px"><li><a href="#e-rem">Remaining is more than the spool holds</a></li><li><a href="#e-name">Color name is empty</a></li></ul></div>' : '';
var name = '<div class="nm-inset" style="padding:12px 14px;border-radius:var(--radius-md)"><span class="sub">Reads as</span><div class="strong" style="font-size:17px">' + esc(fullName(s)) + '</div><span class="sub">brand · <i>speed</i> · material · <i>type</i> · finish (italic = optional)</span></div>';
var body = demo + conflict + errsum + name +
'<div class="fr2">' + sel('Brand', s.brand, 1) + sel('Print speed', s.speed, 0, '<option>Rapid</option><option>High Speed</option>') + sel('Material', s.mat, 1) + sel('Filament type', s.type, 0, '<option>CF</option><option>+ 2.0</option>') + sel('Finish', s.fin, 1) + '</div>' +
'<div class="fr2"><div class="stack' + (st === 'errors' ? ' field has-error' : '') + '" id="e-name" style="gap:6px"><label class="small strong" for="f-name">Color name <span class="sub" style="display:inline;color:var(--text-accent)">required</span></label><input class="input" id="f-name" value="' + (st === 'errors' ? '' : esc(s.color)) + '" ' + (st === 'errors' ? 'aria-invalid="true" aria-describedby="e-name-m"' : '') + ' placeholder="e.g. Charcoal">' + (st === 'errors' ? '<p class="field-error" id="e-name-m" style="margin:0">Give the color a name, even "Unknown". <span class="sub" style="display:inline">server: <code>color_name is required</code></span></p>' : '') + '</div>' +
'<label class="stack" style="gap:6px"><span class="small strong">Colors <span class="sub" style="display:inline">1–3</span></span><span class="row" style="gap:8px">' + sw(s.c) + '<input class="input" value="' + s.c[0] + '" style="max-width:110px"><button class="btn btn-sm" type="button">+ color</button></span></label></div>' +
'<div class="fr2"><label class="stack" style="gap:6px"><span class="small strong">Total <span class="sub" style="display:inline">net, as sold</span></span><input class="input num" value="' + g(s.tot) + '"></label>' +
'<div class="stack' + (st === 'errors' ? ' field has-error' : '') + '" id="e-rem" style="gap:6px"><label class="small strong" for="f-rem">Remaining <span class="sub" style="display:inline">net</span></label><input class="input num" id="f-rem" value="' + (st === 'errors' ? '1,040 g' : g(s.rem)) + '" ' + (st === 'errors' ? 'aria-invalid="true" aria-describedby="e-rem-m"' : '') + '>' + (st === 'errors' ? '<p class="field-error" id="e-rem-m" style="margin:0">1,040 g is more than this spool holds (' + g(s.tot) + '). <span class="sub" style="display:inline">server: <code>remaining_grams cannot exceed total_grams</code></span></p>' : '<span class="sub">To measure it, use the <b>Weigh</b> tab instead.</span>') + '</div></div>' +
'<div class="fr2"><label class="stack" style="gap:6px"><span class="small strong">Spool type <span class="sub" style="display:inline">supplies the empty spool weight</span></span><select class="select"><option>' + esc(s.stype || 'None chosen') + '</option></select></label>' +
'<label class="stack" style="gap:6px"><span class="small strong">Empty spool weight</span><input class="input num" value="' + (s.tare == null ? '' : g(s.tare)) + '" placeholder="unknown"><span class="sub">' + (s.tare == null ? '<span class="prov warn"><i>?</i>unknown, never 0</span>' : tareProv(s)) + '</span></label></div>' +
'<div class="fr2"><label class="stack" style="gap:6px"><span class="small strong">Cost per kg</span><input class="input num" value="' + usd(s.kg) + '"></label><label class="stack" style="gap:6px"><span class="small strong">Storage location <span class="sub" style="display:inline">optional</span></span><input class="input" value="' + esc(s.loc || '') + '"></label></div>' +
'<div class="banner" id="discard-bar" hidden><span style="flex:1">Discard unsaved changes?</span><button class="btn btn-sm" type="button" data-discard>Discard</button><button class="btn btn-sm" type="button" data-keep>Keep editing</button></div>';
var foot = (st === 'conflict' ? '<span class="small muted" style="margin-right:auto">Save is off until you choose a version.</span>' : '') + '<button class="btn" type="button" data-' + (isNew ? 'close-drawer' : 'tab="overview"') + '>Cancel</button><button class="btn btn-primary" type="button" ' + (st === 'conflict' ? 'disabled' : 'data-save') + '>' + (isNew ? 'Add spool' : 'Save changes') + '</button>';
return h + t + '<div class="drawer-body">' + body + '</div><div class="drawer-foot">' + foot + '</div>';
}
function printDrawer(p) {
var pr = printer(p.printer), n = needs(p);
var h = head('<span class="wordmark-mark" style="width:44px;height:44px;background:var(--surface-inset);color:var(--text-primary)">' + ICON.prints + '</span>', esc(p.job), printSt(p) + ' · ' + esc(pr.name) + ' · print #' + p.id);
var fix = '';
if (n.length) {
fix = '<div class="nm-inset panel" style="border:1px solid var(--status-warning)"><h3 style="color:var(--status-warning)">Needs ' + n.map(function (x) { return x.t; }).join(' + ') + '</h3>' + fixers(p) + '</div>';
}
var body = fix + '<dl class="kv"><dt>Printer</dt><dd><a href="04-printers.html#printer=' + pr.id + '">' + esc(pr.name) + '</a></dd><dt>Started</dt><dd>' + when(p.start) + '</dd><dt>Ended</dt><dd>' + (p.end ? when(p.end) : p.status === 'running' ? '<span class="muted">still running</span>' : '—') + '</dd>' +
'<dt>Duration</dt><dd>' + durCell(p) + '</dd>' +
'<dt>Job key</dt><dd><code>' + esc(p.key) + '</code><span class="sub">The identity. Two jobs can share a name, never a path.</span></dd>' +
'<dt>Filament</dt><dd>' + (p.grams == null ? '<span class="muted">not known yet</span>' : '<b class="num">' + g(p.grams) + '</b> ' + weightProv(p) + (p.status === 'failed' ? '<span class="sub">Failed prints record the full job weight. Correct by hand if needed.</span>' : '')) + '</dd>' +
'<dt>Spool</dt><dd>' + spoolLinks(p) + changeSpool(p) + '</dd><dt>Cost</dt><dd>' + (p.cost == null ? '<span class="muted">pending: needs weight and spool</span>' : usd(p.cost) + (p.filaments && p.filaments.some(function (f) { return f.spool == null; }) ? ' <span class="sub" style="display:inline">so far</span>' : '')) + '</dd>' +
'<dt>Use</dt><dd><div class="tabs" role="group" aria-label="Use type"><button type="button" aria-selected="' + (p.use === 'business') + '">Business</button><button type="button" aria-selected="' + (p.use === 'personal') + '">Personal</button></div>' + (p.use == null ? '<span class="sub">Not recorded</span>' : '') + '</dd></dl>' +
(p.filaments ? '<div><h3 class="section">Colors</h3><table class="tbl"><thead><tr><th>#</th><th>Color</th><th>Spool</th><th class="r">Grams</th><th class="r">Cost</th></tr></thead><tbody>' + p.filaments.map(function (f) { var s = f.spool && spool(f.spool); return '<tr><td>' + (f.slot + 1) + '</td><td><span class="swatch swatch-sm"><i style="background:' + f.hex + '"></i></span> <code>' + f.hex + '</code></td><td>' + (s ? '<a href="#spool=' + s.id + '" data-spool="' + s.id + '">' + esc(short(s)) + '</a>' : '<span class="prov warn"><i>!</i>unattributed</span>') + '</td><td class="r">' + g(f.grams) + '</td><td class="r">' + usd(f.cost) + '</td></tr>'; }).join('') + '</tbody></table></div>' : '');
var foot = p.status === 'running' ? '<span class="small muted">Name and weight are captured when the print ends.</span>' : '<button class="btn btn-sm" type="button" data-fake="Archived ' + esc(p.job) + '. Accounting unchanged." style="margin-right:auto">Archive</button><button class="btn" type="button" data-close-drawer>Done</button>';
return h + '<div class="drawer-body">' + body + '</div><div class="drawer-foot">' + foot + '</div>';
}
function changeSpool(p) {
var attributed = p.filaments ? p.filaments.filter(function (f) { return f.spool; }) : (p.spool ? [{ spool: p.spool, grams: p.grams, slot: null }] : []);
if (!attributed.length || p.status === 'running') return '';
if (p.unreconciled) return '<div class="banner err" role="alert" style="margin-top:8px;font-size:12px"><span><b>Can\'t move this one yet.</b> It was attributed to spool #' + p.spool + ' before Extrudex tracked deductions, so nothing records how much came off. Check that spool\'s remaining grams, then re-attribute this print to <b>the same spool</b> to reconcile it. After that it can move.</span></div>';
return attributed.map(function (f) {
var from = spool(f.spool);
return '<details class="chg"><summary>Change spool' + (f.slot != null ? ' for color ' + (f.slot + 1) : '') + '</summary><div class="stack" style="gap:8px;margin-top:8px"><select class="select" style="min-height:36px" aria-label="New spool">' + SPOOLS.filter(function (x) { return x.id !== f.spool; }).slice(0, 10).map(function (x) { return '<option>' + g(x.rem) + ' · ' + esc(short(x)) + ' · ' + x.mat + ' · #' + x.id + '</option>'; }).join('') + '</select>' +
'<span class="sub">' + (f.grams != null ? '<b>' + g(f.grams) + ' goes back</b> to ' + esc(short(from)) + ' #' + from.id + ' and comes off the spool you pick. Cost is re-rated at that spool\'s $/kg.' : 'No weight yet, so nothing moves until one is entered.') + '</span>' +
'<button class="btn btn-sm" type="button" data-fake="Moved ' + esc(p.job) + (f.grams != null ? ': ' + g(f.grams) + ' returned to ' + esc(short(from)) : '') + '">Move to this spool</button></div></details>';
}).join('');
}
function fixers(p) {
var out = '';
if (p.grams == null) out += '<label class="stack" style="gap:6px;margin-bottom:12px"><span class="small strong">Filament used</span><span class="row" style="gap:8px"><input class="input num" style="max-width:140px" placeholder="grams" inputmode="numeric" autofocus><button class="btn btn-sm" type="button" data-fake="Saved ' + esc(p.job) + ' weight · remembered for ' + esc(p.key) + '">Save weight</button></span><span class="sub">From the slicer. Remembered for <code>' + esc(p.key) + '</code> so later runs fill in by themselves.</span></label>';
var slots = p.filaments ? p.filaments.filter(function (f) { return f.spool == null; }) : (p.spool == null ? [{ suggested: p.suggested, slot: null }] : []);
slots.forEach(function (f) {
var sug = f.suggested && spool(f.suggested);
out += '<div class="stack" style="gap:6px;margin-bottom:8px"><span class="small strong">Spool' + (f.slot != null ? ' for color ' + (f.slot + 1) + ' <span class="swatch swatch-sm"><i style="background:' + f.hex + '"></i></span>' : '') + '</span>' +
(sug ? '<div class="row nm-raised-sm" style="padding:8px 12px;gap:10px">' + sw(sug.c, 'swatch-sm') + '<span style="flex:1"><b>' + esc(short(sug)) + '</b><span class="sub">Suggested: same color, loaded in ' + esc(where(sug).short) + '. Not charged until you confirm.</span></span><button class="btn btn-sm btn-primary" type="button" data-fake="Attributed to ' + esc(short(sug)) + ' · ' + g(f.grams || p.grams) + ' deducted">Use this</button></div>' : '') +
'<select class="select"><option>' + (sug ? 'Or pick another spool…' : 'Pick a spool…') + '</option>' + SPOOLS.slice(0, 8).map(function (s) { return '<option>' + g(s.rem) + ' · ' + esc(short(s)) + ' · ' + esc(s.mat) + '</option>'; }).join('') + '</select></div>';
});
return out;
}
var MODELS = { bambu: ['A1', 'A1 mini', 'P1P', 'P1S', 'X1 Carbon', 'X1E', 'H2D', 'H2C', 'H2S'], elegoo: ['Centauri', 'Centauri Carbon', 'OrangeStorm Giga'] };
function peditDrawer(id) {
var pr = id === 'new' ? null : printer(+id), st = D.state;
var h = head('<span class="wordmark-mark" style="width:44px;height:44px;background:var(--surface-inset);color:var(--text-primary)">' + ICON.printers + '</span>', pr ? 'Edit ' + esc(pr.name) : 'Add printer', pr ? 'Connection details · admin' : 'Extrudex connects read-only; nothing is sent to the printer');
var brand = pr ? 'bambu' : (D.brand || 'bambu');
function f(label, hint, input, err) { return '<div class="stack' + (err ? ' field has-error' : '') + '" style="gap:6px"><label class="small strong">' + label + (hint ? ' <span class="sub" style="display:inline">' + hint + '</span>' : '') + '</label>' + input + (err ? '<p class="field-error" style="margin:0">' + err + '</p>' : '') + '</div>'; }
var body = '<div class="row small" style="gap:8px"><span class="muted">Demo state</span><div class="tabs" role="group" aria-label="Demo state">' + [['normal', 'Normal'], ['errors', '400 errors']].map(function (x) { return '<button type="button" data-state="' + x[0] + '" aria-selected="' + (st === x[0]) + '">' + x[1] + '</button>'; }).join('') + '</div></div>' +
'<div class="fr2">' + f('Brand', '', '<select class="select" id="pe-brand"><option value="bambu"' + (brand === 'bambu' ? ' selected' : '') + '>Bambu Lab</option><option value="elegoo"' + (brand === 'elegoo' ? ' selected' : '') + '>Elegoo</option></select>') +
f('Model', '', '<select class="select">' + MODELS[brand].map(function (m) { return '<option' + (pr && pr.model === m ? ' selected' : '') + '>' + m + '</option>'; }).join('') + '</select>') + '</div>' +
f('Name', 'shown everywhere; must be unique', '<input class="input" value="' + (pr ? esc(pr.name) : '') + '" placeholder="X1C — Bench">', st === 'errors' && !pr ? 'A printer called “P1S - Prints Charming” already exists. Names must be unique.' : '') +
'<div class="fr2">' + f('IP address', 'same network as Extrudex', '<input class="input" value="' + (st === 'errors' ? '10.60.1.300' : pr ? esc(pr.ip) : '') + '" placeholder="10.60.1.10" inputmode="decimal">', st === 'errors' ? '10.60.1.300 isn\'t a valid IPv4 address.' : '') +
f('Serial', 'on the printer\'s label', '<input class="input" value="' + (pr ? esc(pr.serial) : '') + '">') + '</div>' +
(brand === 'bambu' ? f('Access code', pr ? 'leave blank to keep the stored code' : 'from the printer screen: Settings → LAN', '<input class="input" type="password" placeholder="' + (pr ? 'unchanged' : '8 characters') + '" autocomplete="off">') + '<p class="sub" style="margin:0">Stored, never shown again. Read-only MQTT needs only IP, serial and access code, no Developer Mode.</p>'
: '<p class="small muted" style="margin:0">Elegoo Centauri uses unauthenticated SDCP, so there is no access code.</p>') +
(pr ? '' : '<div class="nm-inset panel small"><b>After you add it</b><ul style="margin:6px 0 0;padding-left:18px"><li>An <b>External</b> holder is created automatically.</li><li>Add its AMS units under <b>Manage holders</b>.</li><li>Capture starts on the first status report.</li></ul></div>');
return h + '<div class="drawer-body">' + body + '</div><div class="drawer-foot"><button class="btn" type="button" data-close-drawer>Cancel</button><button class="btn btn-primary" type="button" ' + (st === 'errors' ? 'disabled' : 'data-fake="' + (pr ? 'Saved ' + esc(pr.name) + '. The monitor reconnects with the new details.' : 'Added printer. Waiting for its first status report.') + '"') + '>' + (pr ? 'Save' : 'Add printer') + '</button></div>';
}
function holdersDrawer(id) {
var pr = printer(+id);
var h = head('<span class="wordmark-mark" style="width:44px;height:44px;background:var(--surface-inset);color:var(--text-primary)">' + ICON.printers + '</span>', 'Holders · ' + esc(pr.model), esc(pr.name) + ' · where filament can be loaded');
var body = pr.containers.map(function (c) {
var n = contents(c.id).length, ext = c.kind === 'external';
return '<div class="holder"><div class="holder-h"><b>' + esc(c.label) + '</b><span class="muted">' + { ams: 'AMS', ams_lite: 'AMS Lite', external: 'External' }[c.kind] + ' · holds ' + c.cap + ' · #' + HOLDER_IDS[c.id] + '</span><span class="spacer"></span><span class="small">' + n + ' loaded</span></div>' +
'<div class="row" style="gap:8px"><button class="btn btn-sm" type="button" data-fake="Holder label PDF #' + HOLDER_IDS[c.id] + ' generated">Print label</button>' +
(ext ? '<span class="sub">Every printer keeps exactly one external holder.</span>' : n ? '<button class="btn btn-sm" type="button" disabled title="Unload its spools first">Remove</button><span class="sub">Unload its ' + n + ' spool' + (n > 1 ? 's' : '') + ' first.</span>' : '<button class="btn btn-sm btn-danger" type="button" data-fake="Removed ' + esc(c.label) + '">Remove</button>') + '</div></div>';
}).join('') +
'<div class="panel nm-raised-sm stack" style="gap:10px"><h3 style="margin:0">Add an AMS unit</h3><div class="fr2"><label class="stack" style="gap:6px"><span class="small strong">Type</span><select class="select"><option>AMS (4 spools)</option><option>AMS Lite (4 spools)</option></select></label><label class="stack" style="gap:6px"><span class="small strong">Label</span><input class="input" value="AMS 2"><span class="sub">Unique on this printer</span></label></div><button class="btn btn-sm" type="button" data-fake="Added AMS 2 to ' + esc(pr.model) + '" style="align-self:flex-start">Add holder</button></div>' +
'<p class="small muted" style="margin:0">Capacity comes from the type, so a holder can\'t disagree with its hardware. Tray positions aren\'t recorded.</p>';
return h + '<div class="drawer-body">' + body + '</div><div class="drawer-foot"><button class="btn" type="button" data-close-drawer>Done</button></div>';
}
function premoveDrawer(id) {
var pr = printer(+id), loaded = pr.containers.reduce(function (a, c) { return a + contents(c.id).length; }, 0), open = pr.openPrint && print(pr.openPrint);
var h = head('<span class="wordmark-mark" style="width:44px;height:44px;background:var(--wash-error);color:var(--status-error);border-color:var(--status-error)">!</span>', 'Remove ' + esc(pr.name) + '?', esc(pr.model) + ' · ' + esc(pr.ip));
var body = '<ul class="small" style="margin:0;padding-left:18px;display:flex;flex-direction:column;gap:6px"><li>Capture stops for this printer.</li><li><b>Print history is kept</b>, including cost records.</li>' + (open ? '<li><b>' + esc(open.job) + '</b> is open, so it will be <b>closed as unknown</b> with no duration, because nobody will watch it end.</li>' : '') + '</ul>' +
(loaded ? '<div class="banner err" role="alert"><span><b>Can\'t remove yet:</b> ' + loaded + ' spool' + (loaded > 1 ? 's are' : ' is') + ' still loaded in its holders. Unload them first, so they don\'t lose their place. <a href="04-printers.html#printer=' + pr.id + '" data-close-drawer>Show holders</a></span></div>' : '') +
'<label class="stack" style="gap:6px"><span class="small strong">Type <i>' + esc(pr.name) + '</i> to confirm</span><input class="input" id="rm-name" autocomplete="off" ' + (loaded ? 'disabled' : '') + '></label>';
return h + '<div class="drawer-body">' + body + '</div><div class="drawer-foot"><button class="btn" type="button" data-close-drawer autofocus>Keep printer</button><button class="btn btn-danger" type="button" id="rm-go" disabled data-name="' + esc(pr.name) + '">Remove printer</button></div>';
}
function loadDrawer(cid) {
var c = container(cid), inIt = contents(cid);
var h = head('<span class="wordmark-mark" style="width:44px;height:44px;background:var(--surface-inset);color:var(--text-primary)">' + ICON.printers + '</span>', 'Load into ' + esc(c.c.label), esc(c.printer.name) + ' · ' + inIt.length + ' of ' + c.c.cap + ' in use');
var cands = SPOOLS.filter(function (s) { return !s.cont; });
var body = '<label class="stack" style="gap:6px"><span class="small strong">Find a spool in storage</span><input class="input" id="load-q" placeholder="Brand, color, material…" autofocus></label><div class="stack" style="gap:6px" id="load-list">' +
cands.map(function (s) { return '<button type="button" class="slot" style="min-height:0;flex-direction:row;align-items:center;gap:12px;width:100%" data-load="' + s.id + '" aria-pressed="false" data-hay="' + esc((fullName(s) + ' ' + s.color + ' ' + (s.loc || '')).toLowerCase()) + '">' + sw(s.c) + '<span style="flex:1;min-width:0"><span class="nm" style="display:block">' + esc(s.color) + ' · ' + esc(s.brand) + '</span><span class="sub">' + esc(fullName(s)) + ' · ' + esc(s.loc || 'Storage') + '</span></span><span class="g num' + (low(s) ? '" style="color:var(--status-warning)' : '') + '">' + g(s.rem) + '</span></button>'; }).join('') + '</div>' +
'<p class="small muted" style="margin:0">Scanning the holder\'s QR label does the same thing from a phone (existing <code>/c/:id</code> scan session).</p>';
return h + '<div class="drawer-body">' + body + '</div><div class="drawer-foot"><button class="btn" type="button" data-close-drawer>Cancel</button><button class="btn btn-primary" type="button" id="l-save" disabled>Load spool</button></div>';
}
/* ── palette ─────────────────────────────────────────────── */
var P = { items: [], sel: 0 };
function palItems(q) {
q = q.replace(/^\s+/, '').toLowerCase(); if (!/^(load|attribute)\s/.test(q)) q = q.trim(); else q = q.replace(/\s+$/, function (m) { return /\s(into|to)\s+$/.test(q) ? ' ' : ''; });
var acts = [
{ sec: 'Actions', ico: '+', t: 'Add spool', m: 'new', run: function () { openDrawer('new', 0, 'edit'); } },
{ sec: 'Actions', ico: '⚖', t: 'Weigh a spool…', m: 'type its name', run: function () { $('#pal-q').value = 'weigh '; palRender(); }, keep: 1 },
{ sec: 'Actions', ico: '⇥', t: 'Load a spool into a holder…', m: 'load ‹spool› into ‹holder›', run: function () { $('#pal-q').value = 'load '; palRender(); }, keep: 1 },
{ sec: 'Actions', ico: '⇄', t: 'Attribute a print to a spool…', m: 'attribute ‹print› to ‹spool›', run: function () { $('#pal-q').value = 'attribute '; palRender(); }, keep: 1 },
{ sec: 'Actions', ico: '!', t: 'Prints needing attention', m: printsNeeding().length + ' open', href: '03-prints.html?tab=needs' },
{ sec: 'Actions', ico: '◐', t: 'Switch color theme', m: 'light / dark', run: function () { setTheme(document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'); } }
].concat(PAGES.map(function (p) { return { sec: 'Go to', ico: '→', t: p[1], m: 'page', href: p[2] }; }));
var lm = /^load(?:\s|$)/.test(q) && /^load\s*(.*?)(?:\s+into\b\s*(.*))?$/.exec(q), am = /^attribute(?:\s|$)/.test(q) && /^attribute\s*(.*?)(?:\s+to\b\s*(.*))?$/.exec(q);
if (lm) return loadCmd(lm[1] || '', lm[2]);
if (am) return attrCmd(am[1] || '', am[2]);
var weigh = /^weigh\s*/.test(q); if (weigh) q = q.replace(/^weigh\s*/, '');
var sp = SPOOLS.map(function (s) { return { sec: weigh ? 'Weigh which spool?' : 'Spools', html: sw(s.c, 'swatch-sm'), t: s.color + ' · ' + fullName(s), m: '#' + s.id + ' · ' + g(s.rem) + ' · ' + where(s).short, hay: ('#' + s.id + ' ' + s.id + ' ' + fullName(s) + ' ' + s.color + ' ' + where(s).text).toLowerCase(), run: function () { go('spool', s.id, weigh ? 'weigh' : 'overview'); } }; });
var pr = PRINTS.map(function (p) { return { sec: 'Prints', ico: '▤', t: p.job, m: PST[p.status][1] + ' · ' + when(p.start), hay: (p.job + ' ' + p.key + ' ' + printer(p.printer).name).toLowerCase(), run: function () { go('print', p.id); } }; });
var pt = PRINTERS.map(function (p) { return { sec: 'Printers', ico: '▣', t: p.name, m: p.connected ? (p.state === 'RUNNING' ? 'printing' : 'idle') : 'reconnecting', hay: p.name.toLowerCase(), href: '04-printers.html#printer=' + p.id }; });
if (weigh) return sp.filter(function (i) { return !q || i.hay.indexOf(q) >= 0; }).slice(0, 12);
if (!q) return acts.concat(sp.filter(function (i, k) { return k < 3; }).map(function (i) { i.sec = 'Recent spools'; return i; }));
var match = function (i) { return (i.hay || i.t.toLowerCase()).indexOf(q) >= 0; };
return acts.filter(match).concat(sp.filter(match).slice(0, 8), pr.filter(match).slice(0, 5), pt.filter(match));
}
function holders() { var out = []; PRINTERS.forEach(function (pr) { pr.containers.forEach(function (c) { out.push({ id: c.id, pr: pr, c: c, n: contents(c.id).length, hay: (pr.name + ' ' + pr.model + ' ' + c.label + ' ' + c.kind).toLowerCase() }); }); }); return out; }
function spoolHay(s) { return ('#' + s.id + ' ' + s.id + ' ' + fullName(s) + ' ' + s.color + ' ' + where(s).text).toLowerCase(); }
function loadCmd(sq, hq) {
var sp = SPOOLS.filter(function (s) { return !sq || spoolHay(s).indexOf(sq) >= 0; }).slice(0, 6);
if (hq == null) return sp.map(function (s) { return { sec: 'Load which spool? (then type “ into …”)', html: sw(s.c, 'swatch-sm'), t: s.color + ' · ' + fullName(s), m: '#' + s.id + ' · ' + where(s).short, keep: 1, run: function () { $('#pal-q').value = 'load #' + s.id + ' into '; palRender(); } }; });
var s1 = sp[0]; if (!s1) return [];
return holders().filter(function (h) { return !hq || h.hay.indexOf(hq) >= 0; }).map(function (h) {
var full = h.n >= h.c.cap && s1.cont !== h.id;
return { sec: 'Load ' + s1.color + ' · ' + s1.brand + ' (#' + s1.id + ') into…', ico: full ? '✕' : '⇥', t: h.pr.model + ' · ' + h.c.label, m: full ? 'full · ' + h.n + '/' + h.c.cap : h.n + '/' + h.c.cap + ' in use', run: function () { if (full) return toast(h.c.label + ' on ' + h.pr.model + ' is full. Unload a spool first.', 'warn'); s1.cont = h.id; s1.v++; toast('Loaded <b>' + esc(s1.color + ' · ' + s1.brand) + '</b> into ' + esc(h.pr.model + ' · ' + h.c.label)); if (PAGE.refresh) PAGE.refresh(); } };
});
}
function attrCmd(pq, sq) {
var pr = printsNeeding().filter(function (p) { return !pq || (p.job + ' ' + p.key).toLowerCase().indexOf(pq) >= 0; });
if (sq == null) return pr.map(function (p) { return { sec: 'Attribute which print? (then type “ to …”)', ico: '▤', t: p.job, m: needs(p).map(function (n) { return n.t; }).join(', '), keep: 1, run: function () { $('#pal-q').value = 'attribute ' + p.job.toLowerCase() + ' to '; palRender(); } }; });
var p1 = pr[0]; if (!p1) return [];
return SPOOLS.filter(function (s) { return !sq || spoolHay(s).indexOf(sq) >= 0; }).slice(0, 8).map(function (s) {
return { sec: 'Attribute ' + p1.job + ' to…', html: sw(s.c, 'swatch-sm'), t: s.color + ' · ' + fullName(s), m: '#' + s.id + ' · ' + g(s.rem), run: function () { if (p1.filaments) p1.filaments.forEach(function (f) { if (f.spool == null) f.spool = s.id; }); else p1.spool = s.id; toast('Attributed <b>' + esc(p1.job) + '</b> to ' + esc(short(s)) + (p1.grams != null ? ' · ' + g(p1.grams) + ' deducted' : '')); if (PAGE.refresh) PAGE.refresh(); } };
});
}
function go(kind, id, tab) {
var pageFor = { spool: null, print: null };
if (window.PAGE && PAGE.name) openDrawer(kind, id, tab);
}
function palRender() {
P.items = palItems($('#pal-q').value); if (P.sel >= P.items.length) P.sel = 0;
var last = '', html = '';
P.items.forEach(function (it, i) {
if (it.sec !== last) { html += '<div class="pal-sec">' + esc(it.sec) + '</div>'; last = it.sec; }
html += '<div class="pal-item" role="option" id="pi' + i + '" data-i="' + i + '" aria-selected="' + (i === P.sel) + '">' + (it.html || '<span style="width:18px;text-align:center" aria-hidden="true">' + it.ico + '</span>') + '<span>' + esc(it.t) + '</span><span class="meta">' + esc(it.m || '') + '</span></div>';
});
$('#pal-list').innerHTML = html || '<div class="empty"><h3>No matches</h3><p>Try a color, brand, <code>#47</code>, a job name or a printer.</p></div>';
$('#pal-q').setAttribute('aria-activedescendant', P.items.length ? 'pi' + P.sel : '');
var cur = $('#pi' + P.sel); if (cur) cur.scrollIntoView({ block: 'nearest' });
}
function palOpen(prefill) { $('#pal').classList.add('is-open'); $('#pal-q').value = prefill || ''; P.sel = 0; palRender(); $('#pal-q').focus(); }
function palClose() { $('#pal').classList.remove('is-open'); }
function palRun(i) { var it = P.items[i]; if (!it) return; if (!it.keep) palClose(); if (it.href) location.href = it.href; else it.run(); }
/* ── freshness + demos ───────────────────────────────────── */
var fresh = { n: 3, stale: false };
function tick() {
fresh.n = fresh.stale ? fresh.n + 1 : (fresh.n >= 10 ? 0 : fresh.n + 1);
var f = $('#fresh'); if (!f) return;
f.classList.toggle('is-stale', fresh.stale);
$('#fresh-t').innerHTML = fresh.stale ? 'Not updating · data from 09:41:07 <span class="long">· retrying</span>' : 'Live <span class="long">· updated ' + fresh.n + 's ago</span>';
}
function demo(kind) {
var main = $('#page');
if (kind === 'loading') {
var keep = main.innerHTML;
main.innerHTML = '<div class="stack" style="gap:24px" aria-busy="true" aria-label="Loading"><div class="skel" style="width:40%;height:28px"></div><div class="stats">' + [1, 2, 3, 4].map(function () { return '<div class="stat nm-raised"><div class="skel" style="width:50%"></div><div class="skel" style="width:70%;height:24px;margin-top:10px"></div></div>'; }).join('') + '</div><div class="nm-raised card stack">' + [1, 2, 3, 4, 5].map(function () { return '<div class="skel" style="height:18px"></div>'; }).join('') + '</div></div>';
setTimeout(function () { main.innerHTML = keep; if (PAGE.after) PAGE.after(); }, 1600);
}
if (kind === 'offline') { fresh.stale = true; fresh.n = 0; tick(); var b = $('#offline-banner'); if (!b) { b = document.createElement('div'); b.id = 'offline-banner'; b.className = 'banner'; b.setAttribute('role', 'alert'); b.innerHTML = '<b>⚠</b><span style="flex:1">Can\'t reach Extrudex. You are looking at data from <b>09:41:07</b>, and it is not updating. Retrying every 10 s. Saving is paused.</span><button class="btn btn-sm" type="button" data-demo="online">Retry now</button>'; main.parentNode.insertBefore(b, main); } }
if (kind === 'online') { fresh.stale = false; fresh.n = 0; tick(); var ob = $('#offline-banner'); if (ob) ob.parentNode.removeChild(ob); }
}
/* ── wiring ──────────────────────────────────────────────── */
function parseHash() {
var m = /^#(spool|print|load|pedit|holders|premove)=([\w-]+)(?:&tab=(\w+))?(?:&state=(\w+))?/.exec(location.hash);
if (m) { var id = (m[1] === 'load' || m[2] === 'new') ? m[2] : +m[2]; openDrawer(m[1], id, m[3], false); if (m[4]) { D.state = m[4]; renderDrawer(); } }
else if (D.kind) closeDrawer(false);
}
function init(page, render) {
var s = shell(page.name);
document.body.insertAdjacentHTML('afterbegin', '<a class="btn btn-sm" href="#page" style="position:absolute;left:-9999px;top:8px" onfocus="this.style.left=\'8px\'" onblur="this.style.left=\'-9999px\'">Skip to content</a><div class="shell">' + s.rail + '<main id="main">' + s.top + '<div id="page"></div></main></div>' + s.tabbar + s.rest);
window.PAGE = page;
$('#page').innerHTML = render();
if (page.after) page.after();
setTheme(document.documentElement.getAttribute('data-theme'));
setInterval(tick, 1000);
parseHash();
var pq = /[?&]palette=([^&]*)/.exec(location.search); if (pq) palOpen(decodeURIComponent(pq[1]).replace(/\+/g, ' '));
}
document.addEventListener('click', function (e) {
var t = e.target, a;
if ((a = t.closest('[data-set-theme]'))) return setTheme(a.getAttribute('data-set-theme'));
if (t.closest('[data-toggle-theme]')) return setTheme(document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark');
if (t.closest('[data-palette]')) return palOpen();
if (t.id === 'pal') return palClose();
if ((a = t.closest('.pal-item'))) return palRun(+a.getAttribute('data-i'));
if ((a = t.closest('[data-menu]'))) { e.preventDefault(); var m = $('#' + a.getAttribute('data-menu')), open = !m.classList.contains('is-open'); $$('.menu.is-open').forEach(function (x) { x.classList.remove('is-open'); }); m.classList.toggle('is-open', open); a.setAttribute('aria-expanded', String(open)); if (open) { var f = m.querySelector('button,a'); if (f) f.focus(); } e.stopPropagation(); return; }
if (!t.closest('.menu')) $$('.menu.is-open').forEach(function (x) { x.classList.remove('is-open'); });
if ((a = t.closest('[data-demo]'))) { $$('.menu.is-open').forEach(function (x) { x.classList.remove('is-open'); }); return demo(a.getAttribute('data-demo')); }
if ((a = t.closest('[data-soon]'))) { e.preventDefault(); return toast('<b>' + a.getAttribute('data-soon') + '</b> keeps its current screen on dev. It isn\'t redesigned in this iteration.'); }
if ((a = t.closest('[data-spool]'))) { e.preventDefault(); D.list = null; return openDrawer('spool', +a.getAttribute('data-spool'), a.getAttribute('data-tab-open') || 'overview'); }
if ((a = t.closest('[data-print]'))) { e.preventDefault(); return openDrawer('print', +a.getAttribute('data-print')); }
if ((a = t.closest('[data-load-into]'))) { e.preventDefault(); return openDrawer('load', a.getAttribute('data-load-into')); }
if ((a = t.closest('[data-pedit]'))) { e.preventDefault(); var pv = a.getAttribute('data-pedit'); return openDrawer('pedit', pv === 'new' ? 'new' : +pv); }
if ((a = t.closest('[data-holders]'))) { e.preventDefault(); return openDrawer('holders', +a.getAttribute('data-holders')); }
if ((a = t.closest('[data-premove]'))) { e.preventDefault(); return openDrawer('premove', +a.getAttribute('data-premove')); }
if (t.id === 'rm-go') { closeDrawer(); return toast('Removed <b>' + esc(t.getAttribute('data-name')) + '</b>. Its print history is kept.'); }
if ((a = t.closest('[data-add-spool]'))) { e.preventDefault(); return openDrawer('new', 0, 'edit'); }
if (t.closest('[data-close-drawer]')) return closeDrawer();
if ((a = t.closest('#drawer [data-tab]'))) { D.tab = a.getAttribute('data-tab'); D.state = 'normal'; renderDrawer(); history.replaceState({ d: 1 }, '', '#' + D.kind + '=' + D.id + (D.tab !== 'overview' ? '&tab=' + D.tab : '')); var f = $('#drawer [autofocus]'); if (f) f.focus(); return; }
if ((a = t.closest('[data-state]'))) { D.state = a.getAttribute('data-state'); return renderDrawer(); }
if ((a = t.closest('[data-step]'))) { var i = D.list.indexOf(D.id) + +a.getAttribute('data-step'); if (D.list[i] != null) openDrawer('spool', D.list[i], D.tab, false); history.replaceState({ d: 1 }, '', '#spool=' + D.id + (D.tab !== 'overview' ? '&tab=' + D.tab : '')); return; }
if ((a = t.closest('[data-dest]'))) { $$('[data-dest]').forEach(function (b) { b.setAttribute('aria-pressed', String(b === a)); }); $('#m-save').disabled = false; var dc = a.getAttribute('data-dest'), cc = dc !== 'storage' && container(dc); $('#m-save').textContent = cc ? 'Load into ' + cc.printer.model + ' · ' + cc.c.label : 'Move to storage'; return; }
if ((a = t.closest('[data-load]'))) { $$('[data-load]').forEach(function (b) { b.setAttribute('aria-pressed', String(b === a)); }); var ls = spool(+a.getAttribute('data-load')); $('#l-save').disabled = false; $('#l-save').textContent = 'Load ' + ls.color + ' · ' + ls.brand; $('#l-save').setAttribute('data-sid', ls.id); return; }
if (t.id === 'l-save') { var sid = +t.getAttribute('data-sid'), ss = spool(sid), cc2 = container(D.id); ss.cont = D.id; closeDrawer(); toast('Loaded <b>' + esc(ss.color + ' · ' + ss.brand) + '</b> into ' + esc(cc2.printer.model + ' · ' + cc2.c.label) + ' <a href="#spool=' + sid + '" data-spool="' + sid + '">View</a>'); if (PAGE.refresh) PAGE.refresh(); return; }
if (t.id === 'm-save') { var dest = $('[data-dest][aria-pressed="true"]').getAttribute('data-dest'), sp = spool(D.id); sp.cont = dest === 'storage' ? null : dest; sp.v++; D.tab = 'overview'; renderDrawer(); toast('Moved <b>' + esc(sp.color) + '</b> to ' + esc(where(sp).text)); if (PAGE.refresh) PAGE.refresh(); return; }
if (t.id === 'w-save' || t.id === 'w-next') { var ws = spool(D.id), before = ws.rem, nv = Math.round(+$('#scale').value.replace(/[^\d.]/g, '') - ws.tare); ws.rem = nv; ws.remSrc = 'weighed'; ws.weighedAt = '18 Sep 09:41'; ws.v++; toast('Weighed <b>' + esc(ws.color + ' · ' + ws.brand) + '</b>: ' + g(before) + ' → ' + g(nv)); if (PAGE.refresh) PAGE.refresh(); if (t.id === 'w-next') { var nx = D.list[D.list.indexOf(D.id) + 1]; openDrawer('spool', nx, 'weigh', false); history.replaceState({ d: 1 }, '', '#spool=' + nx + '&tab=weigh'); } else { D.tab = 'overview'; renderDrawer(); } return; }
if (t.closest('[data-save]')) { var sv = D.kind === 'new'; closeDrawer(); D.dirty = false; return toast(sv ? 'Added spool <b>#57</b>. <a href="#">Print its label</a>' : 'Saved changes'); }
if (t.closest('[data-discard]')) { D.dirty = false; return closeDrawer(); }
if (t.closest('[data-keep]')) { $('#discard-bar').hidden = true; return; }
if ((a = t.closest('[data-fake]'))) { toast(a.getAttribute('data-fake')); return; }
if ((a = t.closest('[data-delete]'))) { var ds = spool(+a.getAttribute('data-delete')); $('#drawer .drawer-foot').innerHTML = '<div class="stack" style="gap:8px;width:100%"><b>Delete ' + esc(ds.color + ' · ' + fullName(ds)) + '?</b><span class="small">Its print history stays. Prints keep their grams and cost and only lose the link to this spool. This can\'t be undone.</span><div class="row" style="justify-content:flex-end"><button class="btn" type="button" data-tab="overview" autofocus>Keep spool</button><button class="btn btn-danger" type="button" data-fake="Spool #' + ds.id + ' deleted. 0 prints lost their cost.">Delete spool</button></div></div>'; $('#drawer .drawer-foot [autofocus]').focus(); return; }
});
document.addEventListener('input', function (e) {
if (e.target.id === 'pal-q') { P.sel = 0; return palRender(); }
if (e.target.closest('#drawer .drawer-body') && D.tab === 'edit') D.dirty = true;
if (e.target.id === 'scale') {
var s = spool(D.id), v = +e.target.value.replace(/[^\d.]/g, ''), r = Math.round(v - s.tare);
var ok = v > 0 && v >= s.tare && r <= s.tot + 1;
$('#w-after').textContent = v ? g(r) : '—';
$('#w-diff').innerHTML = v && ok ? '<span class="prov">' + (r - s.rem > 0 ? '+' : '') + (r - s.rem).toLocaleString('en-US') + ' g</span>' : '';
$('#w-note').innerHTML = !v ? 'Type the reading and the result appears here before you save.' : v < s.tare ? '<span style="color:var(--status-error)">⚠ ' + g(v) + ' is less than the ' + g(s.tare) + ' empty spool. One of them is wrong. Nothing will be saved.</span>' : r > s.tot + 1 ? '<span style="color:var(--status-error)">⚠ That leaves ' + g(r) + ', more than the spool holds full (' + g(s.tot) + '). Check the total or the empty spool weight.</span>' : 'Saved with the empty spool weight it used, so correcting that weight later re-bases this reading.';
$('#w-save').disabled = !ok; if ($('#w-next')) $('#w-next').disabled = !ok;
}
if (e.target.id === 'rm-name') { $('#rm-go').disabled = e.target.value !== $('#rm-go').getAttribute('data-name'); }
if (e.target.id === 'load-q') { var q = e.target.value.toLowerCase(); $$('[data-load]').forEach(function (b) { b.hidden = q && b.getAttribute('data-hay').indexOf(q) < 0; }); }
});
document.addEventListener('change', function (e) { if (e.target.id === 'pe-brand') { D.brand = e.target.value; renderDrawer(); } });
document.addEventListener('keydown', function (e) {
var typing = /INPUT|SELECT|TEXTAREA/.test(document.activeElement.tagName);
if ((e.key === 'k' && (e.metaKey || e.ctrlKey)) || (e.key === '/' && !typing)) { e.preventDefault(); return palOpen(); }
if ($('#pal').classList.contains('is-open')) {
if (e.key === 'Escape') { e.preventDefault(); return palClose(); }
if (e.key === 'ArrowDown') { e.preventDefault(); P.sel = Math.min(P.items.length - 1, P.sel + 1); return palRender(); }
if (e.key === 'ArrowUp') { e.preventDefault(); P.sel = Math.max(0, P.sel - 1); return palRender(); }
if (e.key === 'Enter') { e.preventDefault(); return palRun(P.sel); }
return;
}
if (e.key === 'Escape') { if ($('.menu.is-open')) { $$('.menu.is-open').forEach(function (x) { x.classList.remove('is-open'); }); return; } if (D.kind) return closeDrawer(); }
if (D.kind === 'spool' && !typing && D.list && (e.key === 'j' || e.key === 'k')) { var b = $('[data-step="' + (e.key === 'j' ? 1 : -1) + '"]'); if (b && !b.disabled) b.click(); }
if (e.key === 'Enter' && document.activeElement.matches('tr[data-row-spool],tr[data-row-print]')) document.activeElement.click();
if (D.kind && e.key === 'Tab') { var dr = $('#drawer'), f = $$('button:not([disabled]),a[href],input,select,[tabindex="0"]', dr).filter(function (x) { return x.offsetParent; }); if (!f.length) return; if (e.shiftKey && document.activeElement === f[0]) { e.preventDefault(); f[f.length - 1].focus(); } else if (!e.shiftKey && document.activeElement === f[f.length - 1]) { e.preventDefault(); f[0].focus(); } }
});
window.addEventListener('popstate', parseHash);
window.X = { unverified: unverified, holderIds: HOLDER_IDS, init: init, esc: esc, g: g, kg: kg, usd: usd, dur: dur, when: when, ago: ago, since: since, spool: spool, printer: printer, print: print, container: container, contents: contents, fullName: fullName, short: short, where: where, gross: gross, value: value, low: low, sw: sw, meter: meter, tareProv: tareProv, remProv: remProv, weightProv: weightProv, durCell: durCell, printSt: printSt, printerSt: printerSt, needs: needs, printsNeeding: printsNeeding, spoolLinks: spoolLinks, openDrawer: openDrawer, D: D, toast: toast, ICON: ICON };
})();
</script>
<script>
(function () {
function node(x, y, w, h, t, s, cls, href) {
var inner = '<g class="node ' + cls + '"><rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" rx="14"/><text x="' + (x + 16) + '" y="' + (y + 26) + '" font-weight="700">' + t + '</text>' + s.map(function (l, i) { return '<text class="s" x="' + (x + 16) + '" y="' + (y + 46 + i * 16) + '">' + l + '</text>'; }).join('') + '</g>';
return href ? '<a href="' + href + '">' + inner + '</a>' : inner;
}
function edge(d, hot, lx, ly, label) { return '<path class="e' + (hot ? ' hot' : '') + '" d="' + d + '" marker-end="url(#ar' + (hot ? 'h' : '') + ')"/>' + (label ? '<text class="lbl" x="' + lx + '" y="' + ly + '">' + label + '</text>' : ''); }
function svg() {
return '<svg viewBox="0 -50 1100 600" role="img" aria-labelledby="map-t map-d"><title id="map-t">Extrudex iteration 2 flow map</title><desc id="map-d">Four pages share one navigation, a command palette and a detail panel. The Dashboard links into each page\'s filtered views; spools, prints and holders open in the panel from any page.</desc>' +
'<defs><marker id="ar" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0 0 10 5 0 10z" fill="var(--text-secondary)"/></marker><marker id="arh" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0 0 10 5 0 10z" fill="var(--text-accent)"/></marker></defs>' +
node(30, 30, 230, 110, 'Dashboard', ['“Needs you” queue', 'stock · recent prints', 'printers · running low'], 'page', '01-dashboard.html') +
node(310, 30, 230, 110, 'Filament', ['saved views + counts', 'Stock / Weights columns', 'weigh session'], 'page', '02-filament.html') +
node(590, 30, 230, 110, 'Prints', ['Needs attention queue', 'All · Running · Archived', 'batch attribute'], 'page', '03-prints.html') +
node(870, 30, 200, 110, 'Printers', ['urgency order', 'holders + Load', 'connection state'], 'page', '04-printers.html') +
node(250, 300, 600, 130, 'Detail panel (#spool= · #print= · #load=)', ['Spool: Overview · Weigh · Move · Edit (+ 409 / 400 states)', 'Print: what it needs, fixed in place · provenance explained', 'Load: pick a stored spool for a holder with space', 'Opens over any page · Esc / back closes · ↑↓ / j k step through the list'], 'hub', '02-filament.html#spool=47') +
node(30, 450, 300, 90, '⌘K / “/” palette', ['spools · prints · printers', '“weigh copper” jumps straight in'], 'hub', null) +
node(770, 450, 300, 90, 'Toasts + badges', ['every save confirms what changed', 'nav counts update immediately'], '', null) +
edge('M262 85 L306 85', 1, 262, 76, 'views') +
edge('M180 30 C180 -18 705 -18 705 26', 1, 395, -8, 'Review N prints') +
edge('M110 30 C110 -38 970 -38 970 26', 1, 520, -30, 'Open printer') +
edge('M145 140 C145 230 330 250 400 298', 1, 150, 225, 'spool / print rows') +
edge('M425 140 L470 298', 1, 452, 230, 'row / ↵') +
edge('M705 140 L640 298', 1, 680, 230, 'row / fix') +
edge('M970 140 C970 230 860 270 800 298', 1, 900, 235, 'spool · + Load') +
edge('M180 450 C180 400 240 380 248 380', 0, 120, 420, 'open anything') +
edge('M850 380 C900 400 920 420 920 448', 0, 930, 415, 'after save') +
'</svg>';
}
var FLOWS = [
['Morning check (≈1 min)', ['<b>Dashboard</b> opens on “Needs you”', 'Review 3 → <b>Use</b> the same-color suggestion', 'Badge on <b>Prints</b> drops as each one clears'], '01-dashboard.html', 'Start on the Dashboard'],
['Weigh the low spools', ['<b>Filament → Low</b> view', '<b>Start weighing</b>: type the scale reading', 'See before → after, then <b>Save & weigh next</b>'], '02-filament.html?f=low', 'Open low stock'],
['Load a spool into a printer', ['<b>Printers</b> → A1 AMS Lite → <b>+ Load</b>', 'Filter stored spools, pick one', 'Toast confirms; the holder fill updates'], '04-printers.html#printer=3', 'Open A1'],
['Find anything', ['Press <b>/</b> or <b>⌘K</b> on any page', 'Type <i>copper</i>, <i>#47</i> or <i>weigh black</i>', '↵ opens the panel right there'], '02-filament.html', 'Try it on Filament'],
['Someone changed it first (409)', ['Spool #47 → <b>Edit</b>', 'Demo state: <b>409 conflict</b>', 'Side-by-side; reapply your change, or discard it'], '02-filament.html#spool=47&tab=edit', 'Open the editor'],
['A spool with no empty spool weight', ['<b>Empty spool weight unverified</b> view (7)', 'Weigh tab explains why it can\'t weigh yet', 'Pick a spool type, or weigh the empty spool'], '02-filament.html?f=tare#spool=44&tab=weigh', 'Open #44'],
['A printer drops off', ['<b>Printers</b>: A1 sits first with a warning border', 'Toggle <b>dev today / + feature branch</b>', 'What happens on reconnect is spelled out'], '04-printers.html#printer=3', 'Open Printers'],
['Label new spools', ['<b>Labels</b> → Needs a label (4)', 'Previews at real 51 × 21 mm proportions', '<b>Download</b>: they\'re marked printed on success'], '06-labels.html', 'Open Labels'],
['Load spools at the printer (phone)', ['Scan the <b>AMS Lite</b> holder label', 'Scan spool labels: each loads, returns or moves', 'A full holder says so; nothing changes'], '09-scan-holder.html?c=5', 'Open scan session'],
['Weigh from a label (phone)', ['Scan a spool label with no session active', 'See where it lives; type the scale reading', 'Before → after, then <b>Save</b>'], '10-scan-spool.html?s=41', 'Open #41'],
['Fix a wrong attribution', ['Print <b>Benchy_x4</b> → <b>Change spool</b>', 'See: 46 g goes back to Elegoo Black', 'Pick the right spool; cost re-rates'], '03-prints.html?tab=all#print=211', 'Open Benchy_x4'],
['Add or remove a printer', ['<b>Printers → + Add printer</b>: brand filters models', 'Remove asks for the exact name', 'Refused while its holders still hold spools'], '04-printers.html#premove=3', 'Try removing A1'],
['Palette commands', ['<b>/</b> then <i>load copper into p1s ext</i>', 'or <i>attribute bracket to black</i>', '↵ does it; a toast confirms'], '02-filament.html?palette=load%20', 'Open palette'],
['When the data is not live', ['Mockup pill (bottom left) → <b>Simulate polling failure</b>', 'Header turns amber, banner says the data\'s age', '<b>Replay first load</b> shows skeletons'], '01-dashboard.html', 'Open Dashboard']
];
function render() {
return '<header class="page-head"><div><h1>Flow map</h1><p class="sum">Iteration 3 · every screen, how they connect, and <b>' + FLOWS.length + ' flows</b> to click through</p></div><div class="actions"><a class="btn" href="../../iteration-2/screens/index.html">← Iteration 2</a><a class="btn btn-primary" href="devices.html">Devices →</a></div></header>' +
'<section class="map nm-raised" aria-label="Flow diagram">' + svg() + '</section>' +
'<section class="stack" style="gap:12px" aria-labelledby="sc-h"><h2 class="section" id="sc-h" style="margin:0">All screens · <a href="devices.html">see them on phone and tablet →</a></h2><div class="flows">' +
[['01-dashboard.html', 'Dashboard', 'Needs you · stock · recent prints'], ['02-filament.html', 'Filament', 'views · weigh session · panel'], ['03-prints.html', 'Prints', 'attention queue · history'], ['04-printers.html', 'Printers', 'holders · load · admin panels'], ['05-lists.html', 'Lists', 'the 5 name parts + spool types'], ['06-labels.html', 'Labels', 'spool + holder QR labels'], ['07-access.html', 'Access', 'people · sessions · API tokens'], ['08-system.html', 'System', 'weekly report · audit · device'], ['09-scan-holder.html', 'Scan: holder', 'phone · load/return/move'], ['10-scan-spool.html', 'Scan: spool', 'phone · weigh from a label']].map(function (s2) { return '<a class="flow nm-raised" style="text-decoration:none;color:inherit;padding:14px 16px" href="' + s2[0] + '"><h3>' + s2[1] + ' →</h3><span class="small muted">' + s2[2] + '</span></a>'; }).join('') + '</div></section>' +
'<section aria-labelledby="fl-h" class="stack" style="gap:12px"><h2 class="section" id="fl-h" style="margin:0">Try these flows</h2><div class="flows">' + FLOWS.map(function (f) { return '<article class="flow nm-raised"><h3>' + f[0] + '</h3><ol>' + f[1].map(function (s) { return '<li>' + s + '</li>'; }).join('') + '</ol><a class="btn btn-sm" href="' + f[2] + '">' + f[3] + ' →</a></article>'; }).join('') + '</div></section>' +
'<section class="compare" aria-label="What changed"><div class="nm-inset"><h3>Iteration 1</h3><ul><li>“Prints” and “All prints” were dead ends</li><li>Edit left the list for a separate page</li><li>A spool in an AMS slot or low-stock list went nowhere</li><li>Every data point was a loud chip, so a legend was needed</li><li>No freshness, loading or error state</li><li>Invented “slot 2” positions the database doesn\'t store</li></ul></div>' +
'<div class="nm-raised"><h3>Iteration 2</h3><ul><li>Every spool, print and holder opens one shared panel, deep-linkable</li><li>Dashboard leads with what needs doing, each item one click from the fix</li><li>Chips only for state; provenance is quiet text with a tooltip</li><li>Palette, badges, toasts, j/k stepping, Esc/back to close</li><li>“Live · updated 3s ago”, with an honest offline state</li><li>Holders show fill (“3 / 4”), not tray positions</li></ul></div></section>';
}
X.init({ name: 'map' }, render);
})();
</script>
</body>
</html>