/* ================================================================
   SECTION: TOKENS+CSS
   Fenestrate design tokens, base styles and components.
   ================================================================ */
/* Poppins inlined as woff2 data URLs (latin subset) so the brand typeface
   survives offline and captive wifi. The Google Fonts link above stays as a
   harmless fallback. Part of SECTION: ASSETS. One line per base64 string. */
@font-face{font-family:'Poppins';font-style:normal;font-weight:300;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2');}
@font-face{font-family:'Poppins';font-style:normal;font-weight:400;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2');}
@font-face{font-family:'Poppins';font-style:normal;font-weight:500;font-display:swap;src:url(data:font/woff2;base64,d09GMgABAAAAABssAAwAAAAAOZgAABrdAAQBBgAAAAAAAAAAAAAAAAAAAAAAAAAAGyAcMAZgAFwK4UTNOQE2AiQDhjgLgx4ABCAFgwYHIBscLbOibo5aMlGUDEYt+K8TuDHEfAN94oQ4IrCF5RM1Tsoo65SU37KChjT23tXouedKtA6muAMf+VEtbkEMrSkjJJltiai1f3tm70MI9XMRJsIQK3JRURqFQpWKc6QJXTTwHtCc/Q94HdPiCRIjRpRkI04SIkoE87BBrAEq5lSoybtCS3te5aon2nOq+u9XVYZzEjyM3kTBykuqLb75mmU8ALJ3/J3fX3f/aKw1S5w5yGq2Qux0yGav7UzU/3+37H3+EHkXTqpmq9TbFJEPn1HizIYVjxic7YaiWdFOxDrzIWYrYglIBfD3Osv2m2bkA/LdBclJdVA0UajLzC9D3RVdqq/3vy1Lf7T7116SltB7ZC2xFNI6zO1V2ZQs3+7caEMAFXFFda4NNEWKoiSVIdMUmDJ/Twylq9zjXv2ezuFpouYlBBnI33suAmyVZDq/4ydVBggVCJgfvTC+Q3AIAuxR1yvbyaYLKnUTCbnvZdjzUhDonVqAc3SvXEOO4u5ZJxcdXh7XmUsSDXwhdcUKTPi/I6tYmuvFkddDPWV8ZdaoAm2/cD96ZSDZo9kplL9gPh9T+6nTUzGpLIT2le2rbmqSj5g/x/w4LR9+/jrw166/VoKfF/688+jhE/EBbP8F9h4GGJsA+QJ492aAIPH4QXZ+BLXJ8H9vCeA/B8ZUVcj91C3jc+dx551OzfATO2tKOBycmICivYgsZ9gz019gHgV65wsVdgM3zusYAWKXz1BzDEPF5ew1AYOHiQoCQ6yMIRztxkKkTpCP6MExlLMBTUMM0oDu8l/ZsubcOOys8HP6Bx29SLRNSe4k/ibSeQtrgIaUzKAEdE19Ki2CDFi20vC9JR6brY1g6++494npesge8OaQJDJsUBcIK4dqntTfo5Ua0FSLULLyegqhZFfKa4rsO5fc82DkNBaC7dLdEGjGZXhRth+ezPke5+ZMLDZTYgQGHFLsgjfapECsWC8WWAwlyFom4XMiwck+nmLYY51T0krHaSVAaVLwTts8/JLwKjgnzkZgKp7ZvaF5KqcpSUKUwEqKrStzuAgRJWYW49RJn/iqVKvBfcymyiuO/xfgXSfZyvtMWDHc4781oaBWiJpyqxAlyf6kNMfivBLVTLBOVhA6YiKflJMCabY7w0NHUbLrsFauXtdxoTYxsUCYjaA9zqcOyfR3B/La56nUu57QSppfkk4zXyDDpnZI02OOhk6eEOqb4CvryRJSYG/NkvcTlFkSBwgIWizwQLGdRFpZiwAGyK6+eQ99Fh25q8KRPdScrZWl/T40uQg/wQsOE9vq3axgpOmfxvSVObSEPeNFdjMWbWIezp48V5z60aGAT/xhHOUHKapNrN9MuFSnq6GcPmoQa7ivD0exfj/QcZBMRtLNLDAO76yPy37bnwu1m2KW7mIrg7zt4JMSYMgqlREPVQZtorH7sFKnpdhHkd2c91pxvWXaHRaHHace/6WSp9xeR5jxxtUEnx7Qqhl4xXi/bWcTc4L3bMAnIiabLNOmEDTMmxtsbpI0RFnCpqprqa58X4altVEAw5Z+RrOhkUp0zJBrm+1M2j2HUgG6ujXIMjH0oeVx7pgv+g3c27ZjlYkl2Qwji7ppKLTvESCjLVurcRZ3t3aNexZOCRZ3vtk8XUq1nfsd2lVle0KW43Ra8+jf9Sbf/uRm3gvtHRiByOjdS1HN00eYYZOFb6RPo4QRYwvJvjL3ougPFbhUUCVH6cFBll3F+RwcjT6PUMDK5vWY0QNfLjwEWAPi+vZBDLSzQC1zPcw8l2T1JP0CqY9NwFSUuo/PGTOjIztO7i661HZ6z1KJloqGtKbjKju/NzL91eHunLtjMRgVoMGSBSZPX6oYILy33GVCMy1MSrFUE0RkvcFytEGwBJ247F2YRMLJLB1sqxglFpWe5JuZ8DXtPDkhAr3/VbpKB/vF1Bk5Y7PnPU3AIuTtTRpcC4KQnRbUsEQL5aRdeezZjT3BWcIs9h3fTUAUQoajfmrnnGm0S+QN1yLQ2DLkPH4R6hu6aonELNmZR4FLGCpwztOKbH50xmNrP+dLuxDiee6VHwmzWFpBNfV8gGRTh8Uu2RCI+PoEHKxY/VTekhysxetAk/gBBsSKU82yrANxs722qfEvDtgq1QrOkSebtUOvr5Izt8RUs2747Q1thkZcGFxeGehxCll+Hu5A1nWWWvAODUnBOtI0mtMJqRnLTzuPzpYED+GxjYh3AH5ntPmy5SJWluXA1uMsnjiw+QolS7mmYwsInbF3FUUpACkSEBXInkbJkHPgHEMwuMgSz63DTxc1bgxa4ndKNpxcttmxJ/BeEwrU/0qKRdmznMlmQAp7E1ZqIVZHiLcaM5CC09gtircbXrRAmcEmPPUF82O9QwIGi4MeWSKNBukOcp2xOKhbuYlQWEKrdyq/9Zr46RXoegIQfocnJQ8svkcOszslxnPvgcZsQKlUDZGWWuBa+oo5AXoqH424D2cfK0SWU6UKem72wus7XNq6seMzfWi8sD8GV1rRV0Kn9wHLdVw7sIFNzrD0RY2dxiB619+2WfJdwqV7VNwu+2zeLdu8k2JCWzrLHBYjYLQGwVXwuYUe7M7pbhVfZ8b7PuX5bJ/IBe4Eg9rKkW/S2XguYSkObeoK8J7n72vkdNd/lrnc83160OkCXSbLPD3Vo9OtC8m9Uzl911y2bb0J9XWVfdda6YsIHp7bn8uuB+UArjotYGoR1mN7NVH6rh78ANojFssByNrKYtPxqdm+ceSP0bEM83VdI/dEeGUHUNyUUFzNM1uFH+hGvgn/eEm8uiK4nM+VY9Sy5/0+AQB+qqXxFiX05XU6NKSA39Qx43UOOilpxJSxyW+dkoMacz8HlDdpHG//7HEtBMup4szJCe0KkLcg7U0j/HmkV5+5sf1LMU0q8ed30rI7a81ub1TipO3XJy4cwsydaK/dPtE8yTXJYNxAvEa2+k5nARb9enV3mocnj7usjgemfrohJUWfTs01HUJXJU+6rJ58+QPlBysuZR6cXbEBe7LR+Fmo3VRxdFWwseII5kSj8bOkeU5FyNnoqZ+FlFUks5PNDypGih2h3nJdN+b43JuCMH06SynQextuyoVuc0idM7glEZZn/yyY9hSYCkHz5ClXxnZl4MY2x2VnT77yDeS0GHRCIbfI5Qa9FurlpUuXjnjOkusLzBbe9Il4M+/DUDIqCAtsZpPZzOOVTwJUGI3hbSS5ooXCdfNlxR5t6le9WQSC1JzDYutw2UU8NNCSljY3KXG8dmRY0tpj3TB/754Zeqlq5GQbwUVRijiueGowbq9JG9rvwTeWtk9Ca73YLevq46tqJ7UD4dQkJZ5YtyXSUJ/kSFbsH9oZXuqAeUM4zXwyBeOLW6xRy0silrfYiYZ55Hmkxb22WiNXOKJXQDlj7FrdtTE39V3gwvzOSIUkEqzBwQhO/O5oeKDLE/bSBez01q+WLePmQ0dazyrBukfWaaOaeRIej6Cg2BDZwhd3YsT+iRoA56m5/ou3Bbo3unRNdXIvi8MQctl8xfQm/5aZnZWN3R0VMtnsipoi0QWu67YeeAMzq6sklfkUI70QMf8ROIg4FWyavZaqaFjYFFjdRJULeFxEQJNYWCUJzkQtGCgM0s9Mxs/WZsCvM2n+XviDo9yx3rM+8OsH7ocQ3q65oNRlEQ01UlwjV8FAPYiucVb9ZEvzYSWdKZUYpTKpSpIvIN1r2H0STjq2UDVFnX6LNpUTWYIKBqNeKaE31heqqltthN29Tf4VaP0Ede2JgwaZWKzWSnmyIkQk0YphQn90vzeuFS39B9RHPXSatZ6qLmqg0qx0BsNwezbi5CNIeRtNqWylKSnDEUfrxCtiNpdTPrJMsqyQyZTzyGcv6PhcpkYiFqmlDI4WEcB3qxAKQ4o0z2sxZVKQWiqnRtnUP7NlPvrJ6YHcnbV6Z723OdhQO7pPpCgUy1Q8nkzN50rUMpDOufXPsWL57X9GwOKJ7ih35D+9A5qVy5t/D1D/RXdzaWVfZV2Aujxwc1ppFUVO+4ZO/4Vaz6E5KihC54UE+P/56ZzdetPaCi19RZVdQtlcc8eBpxSZSrSqwlktaqk5d6A8PzkzLEGeiKEpEhqpfavmLGkfba79urN/3ZwlLkn6VKUN09K4s9i6tmLZ7AcP5q9RUkUkrJZAUpHy+NR0PYH4IxEeLcnIX9Lx38js/0Y6i+97BC0CeG0rKi2k0Q3VJHHMyARpJZGiJXN4Gp0ffgnjHxJxnLHku3dIAZkiZrPW/rIRMr9yDu6wlTYfbMCULxhy0Xjiei7HW1TE8dYXinku2tACTPnB+uayQZtzsAo2Dw8ZbFvr6mybhnTN/47822UdmNXZNTCvu+V9C5yxXX7qePpDg6P/ZL8D/h12YK/cdtwmoSOAPN7pohroblEqOajet9jhrZ5sCbL3WSdqS+at1trNeKow2aFteAQlSb9iQ3OluXDG9RmBc8OvHJ76khJewOGdcg6H+xH/CnyT6QWXA7hTOMvwdrINztgflDh8AeQlkdfh5ne/ab7/7SY60vMi9XkqzEVNwSHoSdQUFIwCJniHzbnDdKaMhWPQkxw7+paJyuoLOa2uqOaK3RJq/UMG0vF8RyPL5EtAR55qm+h0B+sTzxs6OuD71wcVM7pmXaaXqh7r1m2UEYaO2pfIKi7W0Qc+2RZtjpEcKvg3IVI3FUceSPF5fHw+j05/h/jgXnAziWfldHPuMdkIA5+x6IJDGG7IZBchHLa1niit7K8INvuyEBo9/wYxtWaEK4owZXHUAhrD0cBQwKRhxykbaht1wOnh0xqdRqHUaTSn0VNGeVsPU6nsZkrbjKdgcDhweHbQcPcV5CoCXMHIleGBFVM2TumDsyNdy2ibaP3LycvJsMD2k61/89uVb/t+sv1s79/yftX7PigavjX6Dn13W9e33bDdACfLhOVjVuSNQB4GxAiHnJU7K13X3XDtcMRZl+fIg+bUddfyI+O8Dhv2tD+c1vBoWseBOXAAW0eog9uDhpsNpZBZI+prl8gQN/mc1ov16s6XU/jSNplopv4rOkGvzMPhlLkEHZNJMKpwU9KfMsHAhF/eVZAL5W1iYb9eL5zZLpPxy/LPa9FxdJp6zo5Q5T4yqqrpdzMGJSD75Bs609zr098l1lTMdMaYe+4ieLJEV2a16sol5Smmnlj9rLIyTZdE1G+0zFdOryHcnugd9+pHym4nQtb+5RD6MXYHImYNvyRL1ROnnOku1fRKJP1Go6i/V1ys7hIKu7XtGVPNSoStV/RB/qWqMe8Y4kCwrgpTg4u6loStghpiGfmE1ktS8do7hQbPqpoJ1pYxA5UtNui1JefLqDxruN5tl+mzf2zazUPEMhqjViluoSrkaj5foVZQ0XH0/Ve3WTSobF6+dlQgw6LYb0/5t2KtrIjtxmaMpaxCITPifcTGbx4+QsfRwxeeboUz/05uwziQUVIVjWXIofUhYFHeMWNWvqC64JOBWhYXBomfyZmMF5mC4EHoDIm032iQD/SJNRom+voZDMqBmRJNXpkqh6jncPA6ZQ4Op8jJ03GsNrcYfnlbTuHJ2iXCvgT4sfJKybdMKB4tVs/dwMD+GvhllF1aL95r2lVJQaStmy/SD6AjMNuThSKhIR3Folq4EVpFYGvD29OvEkii5JRDz66fpTAQOo4ic+fwnKgzoBjNtBPwz5Ji3l8PfK5K7QskUuTOHD5cu5SfMpYhcdmKiqXF+YgDWeBdMNcBXAwWRQZNmHzEqWtFLZSHSIGUyk1fdN3AzL+O6Qbyc+x+TGfTWnpOnQcwreho62hH88mWk0CPORYz0D7aPNpxbOqxWMbTABYmOiO3vXnSz8l9G3du3wlHSt44fI43DW/lpYAZ218SsZkhrlArXarTiITluNSHqXFBGgi1syhkocJfUQWFNc3ASotL/HbDlQtFOo2UHmoNcWViiS8h50FXomAUS3tYJiAjxdrCpMFjS69ExLu5+ql63TxpxTHn+4iENh18Ro9InhKdT438s2vyeBf47G+G60LEjS5jqBkxN01oX1ZX175clSkJSEgSn8264Td0qd6qVustUsDbHNe4m7EWQZS4SWNUs4XM0kqqsL6xw6+khu5j0/lcQfKJ7V9pDkiiSgUS+IZzf3/EzVMc5snT6RvHOIX3R9N/v8hgXvw9Yv9Dzpq6GjLFgsEwKBQsBo4t9On2+t2fflF3cTG6WMT0+/NC3YxNeX3bdFSiH4JXpaGz0ZYp/a86XGLdxOEpSjcOcbSa1Cj2PZ5Ex8Ru56fyY0rTHUYhvVB/Yu/DtoE0TvFFaJVxOGwxG4eTsYeMRAcBrj49Pv7uXcXyg6efb7GZB6urzTtsz6qqrTYF0uDWABt+rlK22OGQLZpbZLcxMcU+oovnKO08TTmDUS0SMWvKGFxVozYCqbn2LJvGU8lkPCUNg2yriRDXq9QwXYzTqvCEvPdYktVpJQS/25OKCDg91U49k5N7gEo9kJszSoX5HfbDtKLJdbhcdwuGkuP/ogvPW6HwCyeN6uRwfokSIabRvDCtQOo1WeVymDK5URV81OyfaLHUYlWeIkTJ+6kyY20KGpEeujc0dE9oOnRcMzYZIbGk2q2j6XOJWhqNpDXm0XQVpdpYanc2to5Gl2VnL6DBJu+aS+737rE1Y1y7oW6D9zcJOXtkUwT16gmTEmIXRkbow20pEmZhzrWA6Zl70mQEiF9SxCjE8BM1ydNj9vifYkzP1TH4/CJWhIV2Ijb2QnTUj3FZrPT4c1FRQ3G5K41we/Rmg+FmFwgwWNR82EZkcZYmt+CXuo8D5FU6hc7KhKnt7ajd3uFtS4SzRCmdTJayCmbLGpM+j47+PKmgR1kAkT2iZW5rEkwX5xebcHS6KS9fR6eRdWYEGHGkYnoa5UBOzkI6tUv8RimwHOM83FhyuKRWTz/MqIQ0Vc/sOnvGSINv5GwrXmgVjpLXPui9jZ81WDZYDuYeOmftOTNayXjZ//A45QTM7i4zrRipx7kcNn5RlFRkLsfuC6vrZwRy53dPLE9+m2LtWxqgWtLrG7ls9XXMvDEA50vq1NucYV9XVx6Sx3LmHesxhy5z6Da6qirdDtg7vLuyRbufznhWUW1Rznina2BBZ9fA/K6WK8drj19tgVcL1g3rKxTr161eLZOtJh45xq9dBytVW/HdktVjCW5Txpdb7eX12wgB1S24zZhnid0+ghfqPI8N+sf95sDxdc2fm9aD9UDCVJYDlqInW5b0Hb9Sre8LCj4gvgc+oC3pae+VV5OoRXgqSbCyQjIl4uD3ijihlquotzntHlewqTXhKd6IpFWRihNkhfkZQsH7n5tyHhZIOQiSgZIBGQhmjDjzhZL0rAJJzre9cUqfu4RTSw7Vl+njKsicVQRUQ89W2Sk1qV3qLa5srrJNhHQXtSUC36YRFZZoJvCfjBfC4swC+cPAGlOKqSda6XEbQnIG445pEoZUKxidamO9NR+YXo/Wylf2y3Wa0v+ySge6xcp8ZWJSIj+vG8tVx6d4WhFKbzZXm9BcoMojGDgcvEGZi8PJc/O8FblG2VWB/V9k3fI7p/uD+291Qz+I+lagQmuJedwSSrdGqUNUrXXGvGUy6iLNheKtjwIHWSuLMTLu5sdBPgau5pgFfn5ZxkJqjB8TUsr5qhG9j6ao2zbZM5i1VOH6nUuN1qU6GmaFO+v5bBKRpXyyRCQ9PfL/nY6OOh0bcyYq+kwMhG8YxUeeZt+TTwmvyOR3TZNvJiZkTw6vnANWX+yteaSFkuHnYmQu+3rR9kdtLvr0UUv+/OKYg6fPEwvDsw3uTW4Af/gBIB2mSTikxW8XYBV9Ska6iWv84ZnHb8pGJH174HdYwZSLF87iC0dx4MvEwO0IBg/MlYsXGhNAXSQXDwTKxfvxfYKPdw0iwsiZCOmq8QsFuXjhCb7wWwJ4GKHjgV/k4oUvEsCnBmsbORISDA2AwHcAIBcvjOILQzgwkhi4GZHggRNy8cLmBLAh9MVN/CGBrKOJQR8s4q6hQRbZYWj90vQ5TNjKxQtD+MLKBLDTMAE6p4JcvHAwAeyL2HBh50pg3paM0TDNJTqeVaiUqo7zYl8C76avtz+VGZAKXA0rz7MRafJliVLn4N+iNv9U1ATDuayXDnp3HILYolhVrG3FJUqRJ3k3iC5SgKYKX+M0keYrkX25+HyODsJ2/d4YVbKmupHoIpWsbKNAtW4QW6S3+SPXi2p28NpHElnaN7EfjHG+CMMQ8atkad8Y4/0oSwLWH5JjQEAhf6w/wOxdk2Vk0dGApf3j9Dwimf+1cCQt7Rv7uIn//5VdKBAfwtenBov4hfi9CHacb57o2sX5FhoQcBfw4vG+AeD1QfrlXnfZPVxowAZ/gID/3IktP6YkDr07/xUXz0u0PO0cYYlQ+qiR0oU4I0Fu/1+Gg9LzUC9/FRPzH17HVPlbUOXMniHVH7gdwIkTvghydUidh9A+is6kKEl2fbjtUeQVUkhSW6FsBENX1TxNkL34gaSnpLedcgRBVs9RdjIoG8BGX8YTmqfCtctDZyoGCu2GamE5TY9QJOpsaQlW/u3B9jhFh0WOOyK7GrkO00pAzi2re8WujOvvUpljOp8PJnZIFlvKWogCVNsWlTgWX4Ajw7H2j+PNxdS6TANlc1t9MOJoqCL9ao+BT6ukjJ+kfBMH08S8QLySUj/BNRB8EanVbbbmyAzBTnucoHPlNhMHM+V9pAI5YZg4ohFyUUruwXeBLPIuNAjImWliDkjqFTUxSIxJhGcmdill22V4iZpYE90QlTNq7OTul95P2bwtzTjF/2dE2sYGkwma7IB9EwpT4x9fbXve6yaEwxVaelqP8oSQOIgCCJ2SM+j+d3+XFi4NSZFacMfR2CsrHO7E3MOmNCQOAgChAxpCKkLGkTwWkgrzuXheN9VPgjIknnhSloyoDyk58ODkKaD7TaLbZLnJ2gRPLz6m4f1tsAngt0wA8AiwDvOTZMdh/qb67LAALJe9gbyHBZmY4GcXLClhhJp5dEHVqlajVSoy0ruZyhCEKrmWW/OUuiZetoYWrS7DywVNRJtqNRFH+Xi2QrOVxzVZiGRVq+VU8vkyBOV3rTGEg1mlGYVNKqC64GayeA6GfJFKFW6+TSOdp1Wb2aD0+LHLGUhosKUKA5+dioCEpDcpw8B0EZfjcwFeNjVPIAM=) format('woff2');}
@font-face{font-family:'Poppins';font-style:normal;font-weight:600;font-display:swap;src:url(data:font/woff2;base64,d09GMgABAAAAABvkAAwAAAAAOWAAABuSAAQBBgAAAAAAAAAAAAAAAAAAAAAAAAAAGyAcMAZgAFwK4QDMYwE2AiQDhjgLgx4ABCAFgxIHIBvSLLOibo5aOrL/IoE3pPeJMSBGBImIIgz8AIuVGI6AgYf+250S4cEQbPcVxjAee6i92ghJZnn+a43e827PJ+CATxWBZRoZGJ3yERJJR6jZ1VkdJIXYQ+RmTZolxlJji1IEpDYRpC1VigXECigCNlBQjFjOUhOw1JjLeYnp7dW0K7V5PcmVXGn5Ox2I0wlxsjIT+f0nt96/w+xGzoG8uo0MM0j2Ed8Xd2ihjolX4tUSIib/+9KaJpMXOwRU96DVVj1EVSA4aLu/11m2z7Az8gE5DE53Kbp4A/VPUXOd6oNk0I92ZGvBknf2TAts+WiXLYW8vsYb4Olz3d5VCctH7BByBVhUXPTp66sCj6EKaN61hB7vDMux3/oONqKe24QKC0MYgH/3cBRW2yvDpquuyS8GYQboG9bip6PPItliTnio1keTwWC1I3OpNrTqmGwjT4sfuLEQ1D1olb8oWYErm/U9uv4mmQ7cATuYszX1/2WxDe54yx4tp3MTcLAsJUzRrczrtHCr6+7KeivFck/ZgA1gGTA0LEcq80EHD/Zg6SFwv43+eb/z2cdnpz878tm0TdZ86YfhuW6fAWudsOkPoa1sq69gnsG5NctEab2fQo9KdukmfRczYTZv2feUDE9pQYoPU4r0ojFyQxs5IExyGC5QGfZp4aBVpq8Zgx2y+3g9SyO9YhprPc0OXCZV+IVDgYLACCvnZGigP3hIjYEczrKDY6rORnRDkrdkAdvjf81X6yFMkm5BXNA52Ryl7FsqwhmdXWaIHt4BTZnIsMnrucZMbVUAmbBs0WfpfGy2ccs+3nEfENPtiH3gwT1AGjVou8Wahx/Q36KtJn1MIFUdWZ+VVGVP1VuROQihCJ+D03lSEOz50BQs2cGaPKhNErMIydM8FgWqfJB72VIDG5iuuYYC4Q7NVpxNo4qfCeB3IQwx3VcWa/MaqrDQtqLUQRrr/cPyK5bwzreEJ73wMICFfxmea6ok5IKVCmcOYOoLyKn6xoK9fSo3T4iN99m/jGPs8B/T9w9S9mKLn5VeyH+3zDWOFpvm4KT5itse5JKEDqjrWPzbjr0q5DVTEKrmPwmoW4p1ratqTA3NEWhDOGPd4qGlmQuBAq5J6CKktR4iiwaLwInXqnzJxYLueYmqisZMsYW2a7TGIsxK0YuGcClhBOIrNjowFuXmkXIwLG7DBVgoBqXkuvOsLHbCqS49iiArphEX+nKAjZELm3JurZZZna6Dz1ObMI68l0Cifw0TPdkkwmELBzDVV8Hjcmg+bfUmcfyiUQZbJo6FiTeFlezNNcyQ7GcjOS8Jq423jiZcKMPUdLd0xtDAfRZZMKBjxn1GbNeanui14W+hjXz3wZko3bC5AUZrIX/9l6ioJE6TbQpBczi/AHQ0m9+Bj8b7Bhk7sEn0O7dWvx0o2XNqWRWgjeHhBeWc8LGGp+E4X/qrTQvUhfJZnizafFp0DzxmYpCRgfjtQKaKn1nNQ3vuYeqVbKhAenAy/t0LW9C+Ko9eoLOWaFM9KwJCqDeAOkjeVEs5YaKj+G0uva1FeNHTyfow6dw5UfMlP1Eu3milqGT5t6xEx9RVexWkv5iYbk/+aaUyjPCXmMWUTUFCw95p8SR/hLJcW1fbVNJbqz99XKdFwITN+eWzkPtSR7UkG1goaKENlXlO06bp+dVQvXA0+tnJll5GEpkJGbYcWIM0YegYxQsjgbJGnLpqUmPXV4EsFQyiYOjYJVw8FoqDHXem5YlntYpV1pOnKh1XTkNrpMUQGKc8rxLxadFxuZfvSx8rI3mX5AAh7qdUd/xu5bbvLTqO2+0kw3u78KChWBplyjUvCD8Li41Uj92ScZYoy9TcmRO2etAVjDpBnxzR9LzmQC6VZWErU/q8JkU6PWtJ1HfUaYH9Xapf6nSl//Oxz0+v5Byv6nNJq659TgJq6mNwz9DDYAqzETII2u59C0lxzOWEdTnwYFvfNXBiC1fdfT2pl78SXRPqNrtCFhqqWdMPjfEp3Y8NAbE4Pa0oswhpf99FX4qC9EwBC6tYlncGcvNaQfVQaDnIRWMPhqRa1dZY5JdDDOb7rIb2JfCNwrphNk7UtWO0RcOeEhM1rJFbEuBSqbFdp1jzdLhPyj3+tBuz3lb23JC8NOoYwxivCz2MsNbIGjLB554pvr2isWhmilBBGIr5t10kWAVN/ub7zRHDR55tI+t8xKjDWMwcMeICVWva8EutBdFCcBMh6lKMEUowVK0daN3cDJfSQwear8OXXLdfueJLnQeQ4oLF0Jz5lGf1z3IVU8TmX33uRyXgq6XVbern8GVo6g2LG6qibM7GWmeYwKS72qgsPy9y1B7Sg9qbZC6tS+MuLnEe1nKuQPmqnNKHDl3QvAyasD9OhcoYVg6rqVPlgTX8F8fKeFe8ppnKA+X0b8Id+DYFb6zsZDts3B+CPHhJ3esdhF2+PGjzyvyEv/mF9HVHZpTz4sPHGzB4xT600YIOkS1B7WrwLD+d45JpgGsoitSzShpPbWDm4w8iYd/4AUztWHqko9AaZngqd/uXpBrlZ+bLP7davLQ6f2LAhGNoGkWfaBq3xRIp0nYpGEyV7AQdvY7N12pIpS6LShcQy0PmZc1vgw7ibNzK8Tblw12HCRde0tHA9nC4y/ksvTWKP/a69ya51/sT7jb2dCZLE9XAEMtSibCuU8HNvXu50nWWrIEPPNxfO+KRDS3SJE+G1lgMHW2FDkYnSxxYY2Ui5UowKdeL91fwtQ1GOKqV+dvbd1ld/e0byu3fplVjtpgnfN3ZSnofT24Yiq8eZpvmHsplwNqEOyxowQ7fTLnzvezraXMOqAuIDPV6NChRT9dDed6Gkkv1/pvlLx0//l7fYo9DX94DkPY07FHmFI4ZDXNzU8IsH/8onVhdFz19j7riK9vz72ei130x69kvRyGRUWjUf7zu/1Ag/K2MiLfMO95C7Dg4gdN3YIuPdO9Hnhzq4RoMJha6L8V5890XEUcHEa7BUKq3G3ZtenteA6xZRpk9B9paICysCeuwbyqZ3yaXRN2Wx5Yg83RQSVdTdWiBsMAc6qkJKVkg4J6/qYozIvK0kDtud8VZxqOoy3vPI+ALjedBVovJIJOZDPma0/3T9M2Nro2OrE3JtTp22rvZWm7yhKlYJjMWazTGqiAvUW2a/HuIy9FpOaBKrbIYA5pWRp5FCGma1PCDXUgKNb8CL8grJeN1sFEQtytdmJryevz5s7HxmzhV05CfVX3i2Ljj+9MnLTgdUZLL0cH9A+/Y65HHT7sJ9eZgZJPTgzqwrzHV5ogKAtjTUQb/1H0HUlxSI4M1XFdPH9cNtVSC8bPU0j7S4UyvaDAljTkTx+rLWGb/LvUSaOWukqQ9dTv3AB365pODT970H74I+GS6NblMmAwqQqxgTnvqcsxXzjEXCBiIrqemptJnz3U9Iw7PnJtSxtkmOJwJs5gqP9a+xOEs/SPLB8iSvgcfTJqA5TGzrqVe7eXQ/6bRmOLw0S3tw51OT8fuGm1RsMFpVGJaf3QCXld/Y4PSQWMY2XlC46tbp4TlilxWZT1D3RJs2eIajbnLpjuJuWq6fpd317gZT6aQEawxQAq6ZG8dft7kN40HxsNOv0x9BWSYpaeVGhhBXwsRGwXe/r0dnpGWsPLRkZ+oPJ6SL8gV8nAdl4bPPA2O5IeTIKELdLWXE1iiGja7Xi3nuJr4+U5fOelIx/Xu1dE6b0tYcf/+q3I+jyeW8FkCEScnV8IDW13hrvGIKuPudaC62sRimVwMvZ4wvS9ZbGbhsw5+eZ5UamtnqtU+ptQmzeNX2Dd8R+m0ozTiMxTKu8RjL8i4LJpUwONJ8qhMKIcLPj04ThGw7X53IZIitDN4TrV7oN8z3nr1ej/haKOhSuXgsCrY/Y9dvs3iCYQslkDMZuaK+SB74IPPZvnC5ESgN9kP98N+ygCT5OL9b+Tih58B9xs9zTXV3XbnlvzOrSeJJZVEPgFJIMEJgzuYZidTbn/fxu+rVyZOGsoetRdyphpKVYx/Rp4tJ9DzDWU6Nb+vSQsZHw60kSIRMcns5CyKJLmW3jEzOOJdcTlvtXVND41YlYj48ipMa/Px4vJHHTOjP/0ytqAlrSCgbNxbWFRXhjwb+0g2+HkwiTg488/q4bNrtug3G9LurUFEmdos4LCKHWQ5cRUmtxMZBQy+sEC/sZDTKnC4Slrv7XcnCMRL9D03ggDxdMXywTJb2/l2RN2hFiOVy6/iMBwyiOGs4vC5RlrLIUT9OZ/PdrCs4pADHFs5ZihbqqsrO3DM4Ppt9TenuL29qand76p5pQa8rjh/z31vJdwztzbnAb+utCAvf+b+DBNYBbhvO4uIHIGZzXRIZSyHlS3S1xZHq39u8PsjFeWdk6qy2uW8E46KZdmSzXfWA3OAkZXVABaPDXB3Jj4TvB48gFXw0cpde1tzjc3vdQZ29GHQj+Dugtf+ZbFvbIH7L+dkZinGDF53feP2LClAX181+c+uPlO/9syztcTjn4QcQ8D+QO6nnwXWyPGzzwMAHXK43LzssLdYRlbXLJdXLdsdVbctCrrMHGadTMZ0mtl5eRY2EvzdrrNw8oDoJMPazDO27QisbipoYXOsgudsrRS7x/2SG+T763pWSdX5ja7U7pOQH78sn6Evn8f33wo4uxgtjgmshhS0cDiWXEjn0iYcS+3e3cb1USmt3DZwP6SVKqmMnsdZKdQedGbJ8C5JfDE6VysW8MvdFEXjsDOkcn/8OBkbnp0utWdI4g0Yvk7E4ZrdHA3IXGlZVQaUqy3g1ZULcqVKIlWq5BeC50vz/b18nbaHr/SXngfXVzZWTm2szN/G3cIBwfLqkytH+38e/fkwWFud9+8K7jowlNqZCr6dvzt6d+kj86elh+a/H/l+6cOqT8uAe+Xes78Gfr3/7NKcYFYA3mrL8X3cyH6Pww8AJCMPeNo721sfWsELV2Lfdo7GfuUEzqcftmaGeh6C88cmfkoYXp/fyUMucBUzpB4CP12xfe30AFi9uM8DyQUV1Ku6IC5YcKyKJpB55OJ+w2UKRiFBYzAiVLaCRstWiTEeGWpR0ME9UEXlyz2QuNdgEPd75A+HUq7pAl8FIrImdKoY1afF6GylfoFSjMZPsDx1dACrh3o7ZXrHsD2pYuHyKC4XMup1kDHXkKJeSCodqbPrO2VQr1EW8DqyrKRnQ8e/Gi/cV0mFU+H9eMg3s+fUSglLCxMv7NSN2Gv0PTJZn8EI9XVDhbouibSrYBKzTS1kM2SCdiC+Zr0+fj3Pm5du95pbN/tgXvJOKyinVVKO6YIkDX93p8zkm28Kr9p7VEFg8NUKlfFYFZ0vAC8G6nJduyvGg1yjWlmsejUUoIlFMm6OWCamBb4KbBwuzWYDe0NbpaFQhxuVinABHKhtaL5qkT5bUaY3CNqzYfvShwMguHbv/jOnoyt3r/2a+Hs8eP1L7259BZiXaF1dzVCAJhJJuVyxVEQbenJqwQUky8UYuqiWdem8nZsLPqR23CwWhFRrhS4bsxngbtgjMkWfwaDq65Pp9X0y1W8P8/v6ZQWoDnEWRsnUFRbn5uqLdTqtrA7ubfQ/jP1141dQnykJ0AL6rMl/Kae0t021h7wywiVFkBYsvlxJ5slaFZK+ostUbOuEQqPEKKyCTseqDPaIJfrn+96GvXNmUGIxX5MQwAWM4O2wBoqgCBHMq8Nmv5aSVn/7U20mR8QhMdTVeElNW/W2omFYCBa9NyW969wtTX6hOITyFOLE4NtrO9JPwEQ+08UzEWKveCw41uUFOiwuKDtszKaLalicehUUoEICor0gFeB7956Yexl76iXsPGAU4g5hF2z9tv59y9hx69G6o7OOI9YjoL3ltO30/JXEa/FLzadqT81fjb+eCIzYRC9lrj3+k7THxvsn+8HTnj+98y0PoAfe6RbQdOjXCBQuTBteiddWGDWQDyfgpYcWhYdWZDHpkHKzii5lIUIrIkKL0jI/guHaIU2FUUsIrwzTYlERv4LPdwcPBUElJQKFZfcQ8tpxsI8y0xqIcEKw6FLVZiUdYmYBhPem8wQ4H3LjXbiamgBFWF4OZWy+2BQZl0rOc8ZYKvwD1p8I/rAURWsH73Icj6Od8P7wv/dFry8Al2twqj9E3VpTEmoQGlzhHcHGRoeFeDjBBVwc2p8kKxXINRDkPlgCwGts/jpR/hK2TBqa6bYUxUvY0pzqOjrkbvVvNvdF/0EnO3JSl5dvWA5nhuFhxbHgE35k+9gP77A5Vz9ZHL3L5/9/cXFjlsud3RjbHZG3XLWJSHqARD4gkT5Hgg/2eaxHNiHE4c9bnx8LjHHN4QjJEWD1zMOWZqEZaAmEzGQHJgJ7Y+1vFGwsRlAYGhtRam2r2qQPbNMo0JOZSQeFsO/KkCajkMHWzeuY70+f6ECtr66F+pf3CpV6BIPB+YDcYEhPN/Zgv3pt+mO3oeDHp5bKTMtO54Slwu7AQx2ltCGVfE9lBR0wlF9WilGoqHQeVJXlaWvYHLtUynGY10eexl0cA3WeDiJIDLFQyBCRYK/s7YyRuwq1IE1GKFATSIUDpEZzIzHpRSxZQyQUMl1ECQpFJxLpKJSECAbbS84dC4bKzy1Qm87Jg4s9Bb6rvwZGnmwEgqctTKZFwGeaLSw+f8ljmfkCliU18+VtRpNCiS+MwmBSKg0lispLOgy9QItThagl79Yh5zO9cbDQhbDoWBgY+cjWYwOplkZzibHBUlDYaBUna+FOckIWMoFK2cLOSAqYbey64f/Pf7PrJiVGh0Z//yvA7JUzhkx9S/5X3yXFMWMypY1IXR5E2EhX1h+9YOeYnq/IK+QRM5Le3fKXMoNgYEtUej6q0YCJb42Lm01CcjPJ6NjCeJTeDn5a+dpp+9oHyrC4oOFREzmHsJ6wl7aXKhJDXK4YElGBrl0r0u5OivP5fOU5tKo6jl4M3sCp2ExWPpczXtieHIyLCyQLekw0EN9UeMTSEAXSIFqBicDllhKoBSwmraCUyOWaiNQCZhoRicraQiZuzsqiEUEAXXZuUKuAk+aNIIv9wT3I71kdfmT1XgdO1Ci6lTP79dznuKlp01QpqGzifrx175d3rA3vXtM6QDityF17qsfWhs+f9nM/XtQgupUz/vX+z/FTC6ULZWA3M3pMP/F+ZxlMaBQB/qCAM//Kd43f3Qpxzwz8Lu1f9K7+4pqutK/Vghu+1PNmZ5jnW2u3Y9nQ3bptpvBAlW7R7Ehep4Hzyerj8numzC+D/+6Qt3e6XO3+ppozx/3Hz9aAz/xTU5OTZWWTU4EAC4GAq3zs1DSY0y4RO+Qdwu3kupB3uq01TY+T/DK7+WGDTYjXG6zQORU5X6ZK5BKnChReo13ZwesBIhTDnCoW7Ams7R31jT5eZv7zzhEqdYTrftMN6DaezccxqJooHD2ZertGjI6IrTuiTpVo+ZrmSou51RpuGkGtopHq9HRxTFG6gk+GI6NfProza5QqCOTsDKCAqGCH5nRPoYRBeevVhSRdt72Mb6M+X9hb+J2ZyusYPAUGcW8bpGwVG7U92txKLF/lkQq7dJOwMJ0kl60XLz58vYNQnt5x+GrAsCtFvZCgb64tDsfo/tbwSsLtKs5ujbH7tB2QJhGeqnCqpvuURfreMH6/Fb2dUL7mY9+AFymUJXV8M/yi3Y0QihM6YaIsjIrFclhSKPRv6GFmvd7AA1k/edDMDzX+//wf1T8sC5Le/g1h5SYHKYuCVvrRi36HR6zjsM4aBb3ecE2e9Nq6ipIujEqjJL26nkxCdyEeGLi/kdxz5W1ySW9RkaS/TS7PLWW+Whu4H4jJ2rM2ZqHjPqd3B8ivIFtFB+9iE6M9WzoyW2Sf1c/o7eDBPrGARpUIGAynUmnkwJAmrSYkrO5MvMF340YiiDkoFNIS/897MwFVpg4Tzbb4VCKqQQUu3ZxteGgFlpWZKWsBspmZ+KRy8uFzbfPDt5p85g97aWlei5uCrYMfH/ed8K0lEO8CDotm94p0vQAj+q7aXxbW7d4n1hMX/UflQQxe7ktTmeAJnT2PLjqFjm76F9z1oNHLjQZP6KzRP6r24NDLhQVP6Nx/8I99XSFL5bnioVz98gpBwRM6u4suesU/+tzDQi/3QfCEzm4pY8lKDpFnzSVeubncmwAOntDZNXTRIjo641/wviKTasklm1HwhM7m/aOA685gXL4eDE8yIeZfZo3fKTppPI8r+hKXPCm0Fzyhs2PoojH/6IBihAKeD6PgCZ2d8Y+WPWXo5MzC0XDfEdE+PPnqOoQdYKe0Ng8F/u09XcNj6wYwwLWFq5/qIEL/2/vhwXY/+CvsV98U3W8+q31SgbzTbp7qFuu8df3n7Q0QUB+0m95FooE41Z8UwkL/U62DNV+/D6dpzyHPNC9k/zs/gh32Lobxwn4SaLdD3kWCR0aQx9YO3v9MdSMgb9jcrCsPkEd4bYpGQt7tWn4Fte3/RkBC//cEdbyFbfycvCgPVOi+OesQ2muraHTsjZ6b7/W/COna9I2AvGFD8sC2//9OSUlEJIwSqHfCYzbZ9eUIefrkn2eyDbm/hW3Z8h3Ae6+9fRUAPtzOeuXfL/49P/TVQQJYIaD4jzh11Y2K8DeHLSzrB7JUvwG+B+oB5dUI1dqlZhyz8X/VtoMjnoKqrzW4v6O4hICrsqzQf6IjJ6+t4Gx9A5VhzKqXFQFCShAzh5xBuvSCkgWZATnxEFUoOFtS2Cjoss4SttKkQgxp5HlZagZADTiSV0BJACUu66uk7hxZWSB4Kdp0sXwmR8ZCxuKKh74XNFb0iMCyQpLnRA3A9pyDTpeICNHqgZH85mz9zJUT4C1JQ0WD1TkG7gwoZYgg1GWrVOKNz5UdYVGufxmFHJkhGfQqmx4IFjgWq1kxw2FqUEr5gQlTYnvLF5p0Yam0rb6Erv9zFVMxDhREDwb7OrOAnXGYUOXK+aCqSl1ksqrQ9hYLV69KTzg4l5OwCHJXz9W07XVDWo4oKqeMqhXrHzXuijr7wSoKXFoY230loZ5krX5JPoTK71AND0scD/kF7bLtpHAMCRZ0SCWJ8/U/B+7nXaE2sEXpLKkWnmwHCyZI7ZXNexjQXlBPGJisV6YOHVIIyb7+78Av6QG3gT0qHKWMX2LPiggyexHZSiGoi2+7v4RVt1kYL9Oc7aGo+uQHn1StZ0XnOkLlIuIviRYWuU1YMmmHSUidSjapgRu/wxY1hANeAXrHloOWj431Fo5tLvN66fD52GVWV1Styx2sZBJuzTp41HFwalUmaSg7HaY4cdVyPUG0uU26eLNRj4nWl3kNsS7SJlFnyj2feHYueqvmQM9BPgyHuo9E012NpKZLNiE/6nbuzuxi49GBNuWUx5arF6l99leojphbI5tCtRzaNLLyUComo8MDG7LPZgYSCop0VuPI2LHVT9S2WJ9Rv4oGAAAA) format('woff2');}
:root{
  --ink:#202125; --green:#6a9669; --grey:#6b6f76; --faint:#9a9ea4;
  --hair:#e8e8e8; --fill:#f2f5f1; --page-light:#f4f4f2; --cream:#ecebe6;
  /* Fixes run, 7 August 2026, Phase 4 (measured defect): .avatar drew its
     initials in --green on --fill, measured 3.09:1 against a 4.5 floor.
     Same split as --warn/--warn-ink above: --green stays the fill-adjacent
     accent everywhere else; --green-ink is the text-on-soft variant,
     measured 4.79:1 on --fill. The doc that named this fix said --green-ink
     already existed elsewhere in the pack -- grepped and confirmed false,
     so this is a new token, not a rename of one already in use. */
  --green-ink:#4f714f;
  /* v1.6 block 10: split into the mock's own amber/red pair -- warn for
     flags and clashes (advisory, "still fully workable"), error for
     no-crew and destructive (a genuine gap or an irreversible action).
     One shared value read everywhere before this block; see the build
     log for the full site-by-site mapping. */
  /* v2.4 treatment (D14): --warn splits again, by ROLE not by meaning.
     --warn is the FILL value only (a solid warn-coloured background);
     white text on the shipped #a8701c measures 4.20:1 against a 4.5
     floor (fails), so the fill darkens to #9d6818 (white 4.74:1).
     --warn-ink is the TEXT/icon-on-a-neutral-surface colour, kept at the
     original #a8701c -- it was never part of the failing pair (5.00:1
     on its own) so it stays untouched. Every existing color:var(--warn)
     call site (text, not a fill) moves to --warn-ink; every
     background:var(--warn) call site keeps --warn. */
  --warn:#9d6818; --warn-ink:#a8701c; --error:#a8382c; --error-rgb:168,56,44;
  --on-dark-text:#e4e6e9; --on-dark-muted:#9aa0a8; --price-green:#9ec59c;
  /* D23: re-derived against the green-tinted dark page (was #3a3d42,
     blue-grey-derived); only ever read inside [data-theme="dark"] as
     --hair's dark value, per token-parity.js's own allowlist reason.
     Q81 (5 August 2026): re-derived again as the dark theme goes
     neutral -- #37453d carried a green tint that no longer matches the
     now-neutral dark surfaces around it. */
  --panel-line:#34363d;
  --font:'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
  /* D3: card radius 14 to 20. --radius-lg (16px, one real call site --
     .donewrap) retires into --radius, since nothing between card and
     sheet needs its own step. New: --radius-badge (the icon-badge
     primitive), --radius-sheet (replacing the sheet's own hard-coded
     20px 20px 0 0, so the sheet reads as a larger object than the cards
     under it). */
  --radius:20px; --radius-badge:12px; --radius-sheet:24px;
  --ease:cubic-bezier(.25,.6,.3,1);
  /* CB-22 motion language, audited for consistency: two deliberate tiers,
     not a scatter of durations. Tier 1, 150ms with --ease, every press
     state and small toggle (chip, tab, card, disclosure chevron).
     Tier 2, 220-350ms, structural reveals only (sheet open, accordion
     and project-card expand) where a 150ms snap would feel abrupt for
     the amount of content moving. Both tiers die under
     prefers-reduced-motion (see the reduced-motion block below). */
  /* theme layer: --ink, --grey, --faint, --hair, --fill and --page-light stay
     the semantic tokens every rule below already reads. --surface and --solid
     split out the two roles --ink used to double up as (a white "raised
     surface" and a dark "ink block" behind white text), so dark mode can
     retheme text and surfaces without an ink-block button vanishing into an
     ink-coloured page. Light mode values match what every rule already
     rendered before this token existed. v2.4 treatment: --surface is now a
     literal, not var(--on-accent) -- that chain only ever worked because
     --on-accent happened to also be #fff; D14 repoints --on-accent at ink,
     which would have silently turned every card black. */
  --surface:#fff; --solid:var(--ink); --press-bg:#fbfbfa;
  --header-bg:rgba(244,244,242,.92); --tabbar-bg:rgba(255,255,255,.96);
  /* v2.4 treatment (D24, D14): the accent is lime, in both themes. Text on
     it is always ink (13.08:1) -- never the old shared white, so
     --on-accent is redefined to ink in both themes rather than getting a
     dark override; it now pairs with the lime fill only. --accent-edge is
     the 1.5px boundary every lime fill carries in light (3.55:1 against
     the page; lime alone is 1.12:1 luminance there, hue-separated only,
     so glare/greyscale/colourblind readers lose the edge without it) --
     transparent in dark, where the fill already carries 13.8:1 unaided.
     --on-semantic is the text/icon colour for the amber/red fills, which
     are NOT lime and keep the old always-white-ish behaviour's flip:
     white in light (they're dark/saturated enough to carry it), ink in
     dark (white on --green measures 1.92:1 there, white on --warn 2.35:1,
     both under the 3:1 non-text floor). --on-solid is the plain
     white-on-ink-block role --on-accent used to also carry (the toast,
     the segmented-control and pill-toggle selected state) -- its own
     token so on-accent's new ink-only meaning can't silently invert those
     to unreadable ink-on-ink. --sage-deep is the value this pass's first
     draft (D14) put at --green-deep before D24 retargeted that name to
     the lime itself; kept as a named, unused fallback per the spec. */
  /* Q81 (Chantelle's dark-theme rulings, 5 August 2026): the accent moves
     from #d3f48a to #82e578, hue 80 to hue 114. --accent-edge is
     re-derived rather than kept -- the old #6f8a38 reads olive against
     the new fill -- to #3f8a3a, a starting value, not independently
     measured. --on-accent is unaffected, still ink at 10.28:1 on the
     new fill. Light is the primary theme as of this ruling: the new
     accent measures 1.42:1 luminance against the light page on its own,
     so --accent-edge's 1.5px border is what makes an accent fill read
     as a control rather than highlighted text -- every accent fill
     below now carries it, not just the three the D24 pass already had. */
  --accent:#82e578; --accent-edge:#3f8a3a; --on-accent:#202125;
  --on-semantic:#fff; --on-solid:#fff; --sage-deep:#557f54;
  --ink-rgb:32,33,37; --green-rgb:106,150,105; --white-rgb:255,255,255;
  --accent-rgb:130,229,120;
  /* D5 (tints become alpha), item H: the selected nav tab's tint pill.
     rgba over the surface so one formula serves both themes; dark gets
     its own lower alpha below since the lime and the green-tinted dark
     page sit closer in hue than lime does to the light page. */
  --accent-tint:rgba(var(--accent-rgb),.4);
  /* a hairline with more weight than --hair (the checklist tick ring,
     which needs to read before it's ticked, not just delineate) */
  --line:#cfd2cf;
  /* type scale: the sizes every text class already rendered, now named
     and run through one multiplier (--text-scale) so block 10's text
     size control can move all of them at once instead of hand-tuning
     each. 1 is Standard; block 10 sets this to 1.15 / 1.3 per person. */
  --text-scale:1;
  --fs-eyebrow:calc(10px * var(--text-scale));
  --fs-fine:calc(11px * var(--text-scale));
  --fs-sub:calc(13px * var(--text-scale));
  --fs-body:calc(14px * var(--text-scale));
  --fs-h2:calc(16px * var(--text-scale));
  --fs-sheet-title:calc(21px * var(--text-scale));
  --fs-title:calc(26px * var(--text-scale));
  /* radii: --radius is the standing default (cards, sheets, fields);
     --radius-md is the interactive-control step (fields, buttons, rows)
     already used consistently throughout; --radius-pill is every
     full-round chip, button and badge. */
  --radius-md:14px;
  --radius-pill:999px;
  /* D1 (treatment v2.4): one tracking value now, not two. The block-5
     two-token split existed because a single .24em everywhere in v1.4
     widened the stat tiles enough to push a crew chip under the fixed
     tab bar; this pass removes the dense use case instead of tuning it
     -- uppercase itself drops to sentence case app-wide except the one
     page-crumb rule (.eyebrow), so --track-dense has nothing left to
     track and is deleted rather than reassigned, per the standing "a
     token with nothing to do is a token waiting to be misused" rule. */
  --track-wide:.24em;
  /* D8: a shadow scale -- none shipped before this pass. --sh-1 resting,
     --sh-2 raised, --sh-lift upward for anything rising off the bottom
     edge (the sheet). D2 (containers lose their borders) cannot be built
     without this: it is the thing borders move to. */
  --sh-1:0 1px 2px rgba(var(--ink-rgb),.06), 0 1px 1px rgba(var(--ink-rgb),.04);
  --sh-2:0 4px 14px rgba(var(--ink-rgb),.10), 0 1px 3px rgba(var(--ink-rgb),.06);
  --sh-lift:0 -8px 32px rgba(var(--ink-rgb),.16);
  /* v1.5 block 1: avatar disambiguation colours. The brand rule is one
     accent and no second accent colour, so these are not a rainbow --
     six low-saturation neutral tints, none of them green (reserved for
     the single brand accent) or in --warn/--error's amber/red family. Interim
     fix for two people whose initials collide (Charli/Charlie both
     reduce to "Ch"); a photo stays the eventual answer per the person
     record's existing photo field. Same six values in both themes, per
     the light/dark-is-one-token-set rule. */
  --av1:#9aa4b0; --av2:#b3a58f; --av3:#a89aa8;
  --av4:#a3ad9f; --av5:#b09a9a; --av6:#8fa3a3;
  /* Defects run 7 Aug, Phase 5 (measured defect): the fixes run's own
     --green-ink only ever fixed the DEFAULT avatar (text on --fill).
     A collision-tinted avatar (background:var(--avN), the second person
     to share a set of initials) kept plain --green-ink regardless --
     measured on Charlie (--av1) at 2.18:1 light, 1.31:1 dark, both under
     the 4.5 floor and dark theme's own barely readable at all. --av-ink
     is one theme-invariant value (same six-values-in-both-themes rule
     the swatches above already follow) chosen because it clears every
     one of the six swatches: 6.01-6.92:1 computed against each, all
     comfortably over 4.5. avatarSpanHtml inlines it alongside the tint. */
  --av-ink:#202125;
  /* Deliveries run Phase 4 (13 August 2026): the two delivery kinds,
     named by kind and never by hue. Light values are the run doc's own
     (mock 17 FINAL's settled decisions table) verbatim. Dark values
     derived and measured, not carried across -- both light fills sit at
     almost exactly the light page's own luminance (a deliberate near-
     white wash, contrast ~1.1 against --surface, matching the same
     "barely-there tile, the ink glyph and rail do the differentiating
     work" idiom --fill's own tone badges already use, measured the same
     way before assuming it was fine to repeat). Carried straight into
     dark, that near-white wash would glow against a dark surface, so
     dark instead follows the OPPOSITE direction: a muted, dark-hued fill
     (lightness in --surface's own ~15-20% range, not neutral grey like
     --fill's dark value, since these two need to keep their hue
     identity) with a light ink glyph on top. Measured (contrast tool in
     the build log, not eyeballed): dispatch-ink on dispatch = 7.54:1,
     dispatch-edge (unchanged) on dark --surface = 5.23:1; supply-ink on
     supply = 7.83:1, supply-edge (unchanged) on dark --surface = 6.76:1
     -- all comfortably clear 4.5:1, the same floor this app holds text
     to everywhere else. */
  --dispatch:#e7eaff; --dispatch-edge:#8b96d8; --dispatch-ink:#333f7a;
  --supply:#e6f9fc; --supply-edge:#7fb9c4; --supply-ink:#1f5b66;
}
/* dark theme: applied via data-theme on <html>, set per signed-in person's
   preference (see SECTION: THEME). Every surface reads these same tokens, so
   nothing below this block needs its own dark rule. */
[data-theme="dark"]{
  color-scheme: dark;
  --ink:var(--on-dark-text); --grey:var(--on-dark-muted); --faint:#6d7178;
  --fill:#2c2e33; --cream:#2c2e33;
  /* D23 (treatment v2.4): the dark page lifted from a blue-grey hue to a
     green-tinted one at the same lightness, shipped as a two-stop
     gradient via the fixed full-viewport ::before below -- NOT
     background-attachment:fixed, which is janky on mobile Safari and
     kills GPU scrolling on several Android browsers, and this app's
     Week view runs to 3,378px. --page-light below is the flat token
     fallback under that gradient layer, so nothing flashes white on
     overscroll before it paints.
     Q81 (Chantelle's dark-theme rulings, 5 August 2026): the dark theme
     goes neutral. --page-light, --surface, --press-bg and the header/
     tabbar blur backgrounds' rgba source are all re-derived off a
     neutral near-black rather than D23's green-tinted hue -- the green
     the dark theme still carries now comes from the page gradient
     itself (see body::before below), not from these flat surface
     tokens. --accent-edge stays transparent in dark (Q8), unaffected. */
  --page-light:#1c1e22; --surface:#26282e; --solid:#2c2e33; --press-bg:#2b2d34;
  --header-bg:rgba(28,30,34,.92); --tabbar-bg:rgba(28,30,34,.92);
  --hair:var(--panel-line);
  --warn:#d0a15c; --warn-ink:#d0a15c; --error:#d8776a; --error-rgb:216,119,106;
  /* v1.4 block 8: sage lifts on a dark surface -- #6a9669 loses too much
     contrast to carry an accent there. Reuses --price-green, the
     brand's own lighter green already in the token set, rather than
     inventing a new value. --green-rgb follows it, so every rgba(var(
     --green-rgb),x) glow/highlight lifts the same way, automatically. */
  --green:var(--price-green); --green-rgb:158,197,156;
  /* --price-green on the dark --fill already measures 6.67:1 -- no
     separate darker ink needed the way light theme's did. */
  --green-ink:var(--green);
  --line:var(--panel-line);
  /* D24: lime stays lime in dark too (14.44:1 against the new green
     page) -- only its edge and the semantic-fill text pairing change. */
  --accent-edge:transparent; --on-semantic:var(--ink);
  --accent-tint:rgba(var(--accent-rgb),.22);
  /* D8: no resting shadow in dark -- elevation already comes from the
     surface value lifting off the page, matching the model that already
     ships. --sh-2/--sh-lift stay real shadows: dark still needs to
     signal a card or sheet raised relative to *another dark surface*,
     not just the page, which a lift in lightness alone can't carry. */
  --sh-1:none;
  --sh-2:0 4px 14px rgba(0,0,0,.32), 0 1px 3px rgba(0,0,0,.24);
  --sh-lift:0 -8px 32px rgba(0,0,0,.4);
  /* Deliveries run Phase 4: derived, not carried across -- see the
     light block's own comment for the reasoning and the measured
     contrast numbers. */
  --dispatch:#242b51; --dispatch-edge:#8b96d8; --dispatch-ink:#b4bef3;
  --supply:#214045; --supply-edge:#7fb9c4; --supply-ink:#ade1eb;
}
/* D23: the gradient page, a fixed full-viewport layer behind #app (see
   the dark-theme block's own comment for why not
   background-attachment:fixed). Declared only under [data-theme="dark"]
   -- an unstyled ::before has no content and never generates a box, so
   light mode needs no override. z-index is left at auto: as the first
   thing in body's paint order, with every positioned surface above it
   (header 30, tabbar 40, FAB 45, sheet 50/51) and every unpositioned one
   painting after it in document order, it never needs to fight for a
   stacking layer.
   Q81 (Chantelle's dark-theme rulings, 5 August 2026): the gradient's
   own value moves from a two-stop linear gradient to a radial one
   anchored at 0% 0% (near black at the corner, through the app's ink
   at 45%, out to a deep green at 100%) -- the delivery mechanism above
   (fixed ::before, not background-attachment:fixed) is unchanged, only
   this background value. */
[data-theme="dark"] body::before{
  content:'';position:fixed;inset:0;pointer-events:none;
  background:radial-gradient(circle at 0% 0%,#000000 0%,#202125 45%,#144a38 100%);
}
/* D13: corrects styles.css. This rule targeted .lockup img.word, which
   cannot match -- the mark is <ft-logo>, a custom element rendering a
   single path with fill="currentColor" inside .lockup.text-ink, which is
   color:var(--ink) and already themed. branding.spec.js asserts
   .lockup img is exactly zero; this had nothing to select since the PNG
   became the component. Dead code, deleted rather than fixed. */
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
/* Q74 (decision 133): the document's own overscroll behaviour, so a
   pull-down reloads the whole app inside a browser tab exactly as it
   does everywhere else, rather than only inside a sheet (.sheet-body's
   own overscroll-behavior:contain, below, already covers that one
   scroll box). Not pull-to-refresh itself -- that's deferred to Phase 2
   per decision 133 and fen_taska_phase2_ux_notes.md entry 1. -y only:
   horizontal overscroll (back/forward swipe navigation) is unaffected. */
html{touch-action:manipulation;overscroll-behavior-y:contain;}
html,body{margin:0;padding:0;}
body{
  font-family:var(--font); color:var(--ink); background:var(--page-light);
  line-height:1.5; font-size:var(--fs-body);
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
}
#app{max-width:680px;margin:0 auto;min-height:100vh;position:relative;}
button{font-family:var(--font);color:var(--ink);border:none;background:none;cursor:pointer;padding:0;}
a{color:var(--ink);}
/* G defect 1: select/option were never included here, so 19 selects
   render in the browser's default (Arial), audibly wrong beside seven
   Poppins siblings on the same form -- measured on the project edit
   form at 360px (#pjPmId). */
input,textarea,select,option{font-family:var(--font);}

/* type -- every size a token from the scale above, so block 10's text
   size control (which only ever changes --text-scale) moves all of it
   at once. Letter-spacing and line-height stay in true em/unitless
   units already, so they scale with the font automatically without
   their own token. */
/* D1 (treatment v2.4): .eyebrow is the pack's "page crumb" -- the one
   uppercase, wide-tracked caption a screen keeps, almost always the
   heading at the top of a view (Week/Today/a project name). It stays
   exactly as shipped. */
.eyebrow{font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:var(--track-wide);text-transform:uppercase;color:var(--grey);}
/* v1.6 block 5's --track-dense modifier is retired along with the token
   itself (D1). Its call sites (compact day-of-week captions inside a
   narrow grid column, not a screen's own crumb) opt back out of the
   base rule's uppercase/tracking entirely instead -- sentence case, like
   every other rule in this sweep, rather than left silently inheriting
   whatever tracking the removed token's absence happened to fall back
   to. */
.eyebrow.dense{text-transform:none;letter-spacing:normal;}
.eyebrow.green{color:var(--green);}
.eyebrow.faint{color:var(--grey);}
.title{font-size:var(--fs-title);font-weight:600;letter-spacing:-0.015em;line-height:1.15;margin:2px 0 0;}
.h2{font-size:var(--fs-h2);font-weight:600;letter-spacing:-0.01em;margin:0;}
.sub{font-size:var(--fs-sub);color:var(--grey);}
.sub .num{white-space:nowrap;}
.weekcaret{display:inline-flex;margin-left:5px;color:var(--faint);vertical-align:-1px;}
.weekcaret svg{width:11px;height:11px;display:block;transform:rotate(90deg);}
/* v1.4 block 11: the five Unicode-punctuation pseudo-icons the audit
   found, replaced with the same ICONS.chev SVG (rounded caps/joins,
   matching the illustration kit's weight) rotated per direction, same
   technique the accordion's own .car chevron already uses. */
.navchev{width:15px;height:15px;display:block;}
.navchev.prev{transform:rotate(180deg);}
.backchev{width:13px;height:13px;display:block;transform:rotate(180deg);}
.fine{font-size:var(--fs-fine);color:var(--grey);}
.num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum";}

/* header */
.header{
  position:sticky;top:0;z-index:30;
  display:flex;align-items:center;justify-content:space-between;
  padding:14px 18px 10px;
  background:var(--header-bg);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
}
.lockup{display:flex;align-items:center;gap:9px;}
/* Q85 (Chantelle phone review, 5 August 2026): groups the header's
   trailing controls (View options, avatar) into one flex item, so
   .header's own space-between always has exactly two direct children
   -- wordmark left, this group right -- instead of the sliders button
   landing dead centre when it's the lone middle child of three. */
.hdrctrls{display:flex;align-items:center;gap:4px;}
.lockup img.leaf{height:22px;width:auto;display:block;}
.lockup img.word{height:15px;width:auto;display:block;margin-top:2px;}
/* Q21: the page header -- back control replaces the wordmark on a full-page
   drill-down (project detail, variation detail), per mock 02 and rule 9
   (no brand lockup on a drill-down). Avatar stays, same as a tab-level
   header, since rule 9 only names the brand as the drop, not the avatar.
   .pagehead overrides align-items to flex-start: a long "<name> - <builder>"
   title wraps onto a second line rather than ellipsis-clipping (text-size-
   sweep.spec.js's own standing rule -- nothing that computes text-overflow:
   ellipsis is allowed to actually clip); the back/avatar buttons get a
   couple of px of top padding so they still read as aligned with the
   title's first line once the row grows taller than their own 48px. */
.header.pagehead{align-items:flex-start;}
.header.pagehead .iconbtn{margin-top:1px;}
.pagetitle{
  flex:1;min-width:0;text-align:center;font-weight:600;font-size:var(--fs-body);color:var(--ink);
  line-height:1.25;padding:6px 6px 0;
}
.iconbtn{
  min-width:48px;min-height:48px;display:grid;place-items:center;
  border-radius:var(--radius-md);color:var(--grey);transition:opacity .15s var(--ease),transform .15s var(--ease);
}
.iconbtn:active{opacity:.6;transform:scale(.94);}
.iconbtn:disabled{opacity:.35;pointer-events:none;}
/* Fixes run Phase 3b (decision 177, 10 August 2026): the light-circle
   icon-only idiom decision 161 named for a header-row control -- a
   filled pill behind the glyph, distinct from a bare .iconbtn's own
   transparent ground. */
.iconbtn.tint{background:var(--accent-tint);border-radius:var(--radius-pill);color:var(--green-ink);}
.iconbtn.tint svg{width:16px;height:16px;display:block;}
/* Permissions run (6 Aug 2026), Phase 4: the boundary look for a control
   whose action already no-ops safely (stage reorder past either end) --
   dims like :disabled above but keeps pointer events and press state, so
   it never reads as frozen. Paired with aria-disabled, not disabled. */
.iconbtn.muted{opacity:.35;}
/* Q116 (5 August 2026, pre-demo run): the stage update composer's own camera
   control takes the same soft-fill/green pair as the "+" toggles above.
   Scoped by data-action, the button's only call site, not a new class. */
.iconbtn[data-action="stage-camera-add"]{background:var(--fill);color:var(--green);}
/* Q82 (measured defect, CLAUDE.md rule 5): an svg with a viewBox and no
   width/height attribute does not resolve to 24px on its own -- every
   ICONS entry is exactly that. Reaches every icon button, not just the
   one (ICONS.sliders) that surfaced it. The two icons that were
   compensating for the missing rule with their own explicit sizing
   (the kebab dots' width/height attributes, the back chevron's sized
   wrapper span) get their own scoped override directly below, in
   source order, so they don't double up under this new base rule. */
.iconbtn svg{width:24px;height:24px;}
.overflowbtn svg{width:18px;height:18px;}
.backchev svg{width:13px;height:13px;display:block;}
/* Stage content v2, PHASE 2 (6 August 2026): manual reorder's icon-only
   controls -- ICONS.chev reused and rotated, not a new glyph (see
   REORDER_ICON/REORDER_UP_SVG/REORDER_DOWN_SVG, render.js). Selectors are
   scoped under .iconbtn so they win over the same-specificity .iconbtn
   svg base rule above regardless of source order. */
.iconbtn .reordericon{display:flex;flex-direction:column;gap:1px;}
.iconbtn .reordericon svg{width:13px;height:13px;}
.iconbtn .reordericon svg:first-child{transform:rotate(-90deg);}
.iconbtn .reordericon svg:last-child{transform:rotate(90deg);}
.iconbtn .chevup svg{transform:rotate(-90deg);}
.iconbtn .chevdown svg{transform:rotate(90deg);}

/* v2.0 Brief 1B section 5.3: the overflow ("more actions") menu -- one
   kebab button (inherits .iconbtn's 48px tap target), a short absolutely-
   positioned list beneath it, own box-shadow so it reads above sheet
   content without a full modal. First use: project detail's Archive/
   Reinstate and the archive view's per-row Reinstate. */
.overflowwrap{position:relative;flex:0 0 auto;}
.overflowmenu{
  position:absolute;right:0;top:100%;z-index:5;min-width:180px;
  background:var(--surface);border-radius:var(--radius-md);
  box-shadow:var(--sh-2);overflow:hidden;
}
.overflowitem{
  display:block;width:100%;min-height:48px;padding:0 16px;text-align:left;
  background:none;border:none;font-size:var(--fs-sub);color:var(--ink);
}
.overflowitem:active{background:var(--press-bg);}
.overflowitem.danger{color:var(--warn-ink);}
.overflowitem + .overflowitem{border-top:1px solid var(--hair);}

/* R1: persistent storage-failure banner. Not a toast: no timer, no fixed
   overlay to fight sheet z-indexes, just the first thing in #app's flow so
   it re-appears at the top of every render() until the write succeeds again
   or the user explicitly acknowledges it. */
.storagebanner{
  display:flex;align-items:center;gap:10px;
  padding:12px 16px;background:var(--warn);color:var(--on-semantic);
  font-size:12.5px;line-height:1.4;
}
.storagebanner .sb-text{flex:1;}
.storagebanner .sb-text b{display:block;font-size:13.5px;margin-bottom:1px;}
.storagebanner button{
  flex:0 0 auto;color:var(--on-semantic);font-weight:600;font-size:12.5px;
  min-height:48px;min-width:48px;padding:0 6px;border:1px solid rgba(var(--white-rgb),.55);border-radius:10px;
}
.storagebanner button:active{opacity:.7;}

/* view container */
.view{padding:2px 18px calc(92px + env(safe-area-inset-bottom));}
.viewhead{margin:10px 0 16px;}
.footline{margin:28px 0 6px;text-align:center;font-size:var(--fs-fine);color:var(--grey);}

/* cards. D2/D8, item C: the border is gone, --sh-1 does the separating
   instead -- flat none in dark, where elevation already comes from the
   surface value lifting off the page. */
.card{
  background:var(--surface);border-radius:var(--radius);box-shadow:var(--sh-1);
  padding:14px 15px;margin-bottom:12px;
  transition:transform .15s var(--ease),box-shadow .15s var(--ease);
}
.card.press:active{transform:scale(.985);}
/* v2.0 Brief 1B section 6.2: the job row matching the date the user came
   from (a My Week row, a board card, a job sheet's own date strip) --
   "highlight/open the corresponding schedule row" per the brief. */
/* item C removes the container border, but this one was never a
   container separator -- it's a state highlight (the card matching the
   date the user came from), so it keeps an explicit border of its own
   rather than silently losing its only visible signal. */
.card.press.fromdate{border:1.5px solid var(--green);}
/* Project page run, 10 August 2026, Phase 3 (decision 168): the same
   fromDate highlight, moved from card to row -- .stgrow carries no
   border of its own (a hairline bottom rule only), so this is additive,
   not an override of a border this component already had. */
.stgrow.fromdate{border:1.5px solid var(--green);border-radius:8px;}
.cardrow{display:flex;align-items:center;justify-content:space-between;gap:12px;}
/* v1.6 block 8: Schedule Today's job card leads with a type badge (mock:
   .badge) instead of the project name alone -- same tone vocabulary as
   the stat tiles' .statbadge (accent/neutral/warn/error), sized for
   inline use rather than a tile's absolute corner position. */
/* D7, P item: three near-identical soft-tinted circles become one icon
   badge primitive, at three sizes, as rounded squares -- the four-tone
   map (accent/neutral/warn/error) is already correct at each and
   doesn't change. .typebadge is the largest (a card's own leading
   badge), .alertbadge the middle size, .statbadge the smallest (a
   tile's corner accent) -- same relative order as the sizes they
   replace (36/32/22), now 46/38/28. */
.typebadge{
  width:46px;height:46px;flex:0 0 46px;border-radius:var(--radius-badge);
  display:grid;place-items:center;font-size:10px;font-weight:600;letter-spacing:.02em;
}
.typebadge.tone-accent{background:var(--fill);color:var(--green);}
.typebadge.tone-neutral{background:var(--fill);color:var(--grey);}
.typebadge.tone-error{background:var(--fill);color:var(--error);}

/* Stage content v2, PHASE 3 (6 August 2026): the five-state lifecycle
   status chip and its inline picker. */
.statusdot{width:9px;height:9px;border-radius:50%;flex:0 0 9px;background:var(--grey);}
.statusdot.tone-neutral{background:var(--grey);}
.statusdot.tone-warn{background:var(--warn-ink);}
.statusdot.tone-accent{background:var(--green);}
.statusdot.tone-error{background:var(--error);}
.stagepicker{border:1px solid var(--hair);border-radius:var(--radius-md);overflow:hidden;}
.stagepickerrow{
  display:flex;align-items:center;gap:10px;width:100%;min-height:48px;padding:0 14px;
  text-align:left;background:none;border:none;border-top:1px solid var(--hair);
  font-size:var(--fs-sub);font-weight:500;color:var(--ink);
}
.stagepickerrow:first-child{border-top:none;}
.stagepickerrow.current{font-weight:600;background:var(--fill);}
.stagepickerrow:active{opacity:.7;}
/* Defects run 7 Aug, Phase 2: the picker's own explainer, matching
   claude_fen_taska_v2_1_mock_03b_stage_install_v2_6aug.html's .stwhy. */
.stwhy{font-size:11.5px;color:var(--grey);line-height:1.5;margin:0;padding:11px 14px;background:var(--fill);}
.stwhy b{color:var(--ink);font-weight:600;}

/* chips */
.chip{
  display:inline-flex;align-items:center;gap:8px;
  min-height:48px;padding:6px 14px 6px 7px;border-radius:var(--radius-pill);
  background:var(--fill);border:1px solid transparent;
  font-size:var(--fs-sub);font-weight:500;color:var(--ink);
  user-select:none;-webkit-user-select:none;touch-action:pan-y;
  transition:opacity .15s var(--ease),transform .15s var(--ease);
}
.chip:active{transform:scale(.96);}
.chip.outline{background:var(--surface);border-color:var(--hair);}
.chip .flag{font-size:var(--fs-eyebrow);font-weight:500;letter-spacing:.06em;color:var(--warn-ink);}
/* Permissions run (6 Aug 2026), Phase 4: deny_visible. The control still
   renders and is still a real, tappable, 48px button -- never the native
   disabled attribute, which drops press state and reads as frozen. Tone
   only says "not yours to change"; tapping it names who can, via the
   deny-tap toast, not this class. */
.chip.denyvisible{background:var(--surface);border-color:var(--hair);color:var(--grey);}
.chip.denyvisible .statusdot{opacity:.6;}
/* v1.6 block 8: mock's accent-tinted circle, not the plain ink fill --
   the per-collision AVATAR_COLOR_VARS palette (avatarColorVar) still
   overrides this inline for the 2nd+ person sharing a set of initials,
   same disambiguation as before, just against a different default. */
.avatar{
  width:30px;height:30px;border-radius:50%;flex:0 0 30px;
  background:var(--fill);color:var(--green-ink);display:grid;place-items:center;
  font-size:var(--fs-fine);font-weight:500;letter-spacing:.03em;
  overflow:hidden;
}
.avatar img{width:100%;height:100%;object-fit:cover;display:block;border-radius:50%;}
/* Defects run 7 Aug, Phase 5: the unassigned mark -- a muted person glyph,
   not the plain initials tone, so it reads as "nobody" rather than a
   pale copy of a real person's avatar. */
.avatar.unassigned{color:var(--faint);}
.avatar.unassigned svg{width:11px;height:11px;}
/* v2.4 treatment (D24, P item): lime fill, ink text -- this also fixes a
   latent defect, sage-on-sage: the base .avatar rule's color:var(--green)
   was never overridden here, so this avatar's initials matched its own
   background until now. */
/* Q81 (5 August 2026): an accent fill with no --accent-edge border is a
   measured defect this ruling's own text commits to fixing (the new
   accent measures 1.42:1 against the light page unaided). */
.avatar.green{background:var(--accent);color:var(--on-accent);border:1.5px solid var(--accent-edge);}
.avatar.lg{width:44px;height:44px;flex-basis:44px;font-size:var(--fs-body);}
/* Q63 (Chantelle's hands-on finding, 4 August 2026): was 33px, visibly
   larger than every sibling header icon (the sliders/back glyphs render
   at ~24px inside the same 48px .iconbtn). 26px matches the app's own
   existing small-circle precedent (the flag badge, styles.css ~593) --
   not an arbitrary number. The 48px tap target (.iconbtn) is unaffected,
   this only shrinks the visible glyph inside it. */
.avatar.hdr{width:26px;height:26px;flex-basis:26px;font-size:11px;}
.avatar.ringed{box-shadow:0 0 0 2px var(--page-light),0 0 0 3.5px var(--green);}
/* Q22 (decision 46): the second mandatory scoped-mode signal, directly
   under the header on every tab-level surface while a leadership/pm
   account is scoped to 'self'. One tap (scope-exit) returns to team. */
.scopeband{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:8px 18px;background:var(--accent);color:var(--on-accent);
  font-size:var(--fs-fine);font-weight:600;
  /* Q81 (5 August 2026): a bare accent fill, found without its
     --accent-edge border during this ruling's own verification pass. */
  border:1.5px solid var(--accent-edge);
}
/* D24: ink on lime, not white on sage -- the Exit button's own border
   moves from a white-alpha ring (legible against the old dark-sage fill)
   to an ink-alpha one, or it all but disappears against the pale lime. */
.scopeband button{min-height:48px;min-width:48px;padding:0 10px;color:var(--on-accent);border:1px solid rgba(var(--ink-rgb),.4);border-radius:8px;font-size:var(--fs-fine);font-weight:600;}
.scopeband button:active{opacity:.7;}
/* the sliders header control (decision 48) fills sage when a non-default
   view option is active -- weekends shown, or grouped by location --
   same "the control itself reports its own state" convention the
   segmented pill toggles already use. */
.iconbtn.active{color:var(--green);}
/* v1.8 amendment section 9.1: a smaller avatar for the task row's own
   author mark and the multi-assign stacked cluster -- neither needs the
   default 30px size, both sit inline with body text. */
.avatar.small{width:18px;height:18px;flex-basis:18px;font-size:9px;}
.chiprow{display:flex;flex-wrap:wrap;gap:8px;}
/* Stage catch-up run, 7 Aug 2026, Phase 3: the assign opener, a mark not a
   label -- Chantelle, 7 August: "add people to day button should just be
   the plus." 48x48 measured, pill radius, dashed green border; open state
   turns the border solid and rotates the glyph 45 degrees so one drawing
   reads as both open and close. The accessible name lives on this button
   (aria-label); the "+" itself stays aria-hidden. */
.ap-plus{
  display:inline-grid;place-items:center;width:48px;height:48px;flex:0 0 auto;
  border-radius:var(--radius-pill);border:1px dashed var(--green);color:var(--green-ink);
  background:var(--surface);transition:background .15s var(--ease),border-style .15s var(--ease);
}
.ap-plus svg{width:17px;height:17px;display:block;}
.ap-plus:active{background:var(--press-bg);}
.ap-plus.open{border-style:solid;border-color:var(--hair);color:var(--grey);transform:rotate(45deg);}
/* Defects run 7 Aug, Phase 5 (measured defect): the standing Factory/
   Office board cards' own chip row, scoped here rather than on .chiprow
   itself so every other chip list (Team, quick actions) keeps its
   current spacing. Measured cause at 360px: six chips of uneven width
   (name length varies) wrap two-per-line with a name like Charlie's own
   chip landing a fraction of a pixel over the line width, so a 3rd chip
   that would otherwise fit gets pushed to a new row, leaving 90px+ of
   trailing gap on the line above it. Trimming chip padding and the row
   gap buys back just enough width for a 3rd chip to land on more lines. */
.chiprow.tight{gap:6px;}
.chiprow.tight .chip{padding:6px 10px 6px 6px;}
/* multi-assign stacked avatar cluster, overlapping like a hand of cards */
.assigneecluster{display:inline-flex;margin-left:6px;vertical-align:middle;}
.assigneecluster .avatar{margin-left:-6px;box-shadow:0 0 0 2px var(--surface);}
.assigneecluster .avatar:first-child{margin-left:0;}
/* v1.8 amendment section 9.2: an overdue task (rolled forward, still not
   done) gets a stronger amber tint than the standing taskrow rail. */
.checkwrap.taskoverdue{background:var(--fill);}
/* v1.8 amendment section 9.1: the @-picker's own row list -- tappable,
   capped height (crew rosters run to 17+ people), scrolls internally. */
.assignpicklist{max-height:220px;overflow-y:auto;box-shadow:var(--sh-1);border-radius:var(--radius-md);}
.assignpickrow{
  display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;min-height:48px;
  background:none;border:0;border-bottom:1px solid var(--hair);text-align:left;
}
.assignpickrow:last-child{border-bottom:0;}
.assignpickrow.on{background:var(--fill);}
.assignpickrow .apname{flex:1;font-size:var(--fs-body);}
.assignpickrow svg{width:16px;height:16px;color:var(--green);}
/* Add project Phase 5 (decision 184): the collapsed picker button the
   project manager field opens from, mock 15 v3's own .pickbtn/.pl names.
   min-height:58px clears the 48px floor with room for the sub-line other
   .pickbtn users (none yet) may carry. */
.pickbtn{
  display:flex;align-items:center;gap:10px;width:100%;min-height:58px;
  border:1px solid var(--hair);border-radius:var(--radius-md);background:var(--fill);
  padding:0 12px;text-align:left;
}
.pickbtn .pl{flex:1;min-width:0;font-size:15px;color:var(--ink);}
.pickbtn .pl small{display:block;font-size:11px;color:var(--grey);margin-top:1px;}
.pickbtn.empty .pl{color:var(--faint);}

/* buttons. Item C: border to --sh-1, same as the other five containers. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  min-height:48px;padding:0 20px;border-radius:var(--radius-md);
  background:var(--surface);box-shadow:var(--sh-1);
  font-size:var(--fs-body);font-weight:500;color:var(--ink);
  transition:opacity .15s var(--ease),transform .15s var(--ease);
}
.btn:active{opacity:.75;transform:scale(.98);}
/* D4/D24, P item (CTA primitive): ink fill to lime, radius 12 to pill.
   --accent-edge is transparent in dark, so this is a no-op border there. */
.btn.primary{background:var(--accent);color:var(--on-accent);border:1.5px solid var(--accent-edge);border-radius:var(--radius-pill);}
.btn.block{width:100%;}
.btn.quiet{background:var(--fill);}
/* Projects walkthrough fixes run, 11 Aug 2026, Phase 1 (decision 188):
   .btn.secondary used to be a no-op, the same bare .btn look with no
   distinguishing fill or border -- exactly the white-on-white-on-a-
   near-white-page defect five walkthrough findings closed on. Soft
   green fill per the kickoff ruling: tinted green background, green
   ink, no border, shipped tokens only (--accent-tint/--green-ink,
   already proven in both themes by .iconbtn.tint and .navbtn.on).
   Primary is still the solid --accent fill above; plain text (no .btn
   chrome at all) is tertiary. Bare, unmodified .btn stays what it was
   -- the neutral/dismissive look for a Cancel beside a primary action,
   never reclassified by this decision. */
.btn.secondary{background:var(--accent-tint);color:var(--green-ink);}

/* day strip */
/* v1.7 block 8: margin-bottom 4px and padding-bottom 6px, not 8px/12px
   -- part of the named j8/tab-bar 8px clearance fix on Schedule Today
   at 360x800; both this pager and the strip below it are shared with My
   Week, so the trim is small and uniform rather than Today-only. */
.weeknav{display:flex;align-items:center;justify-content:space-between;margin:2px 0 4px;}
.weeknav .label{font-size:var(--fs-sub);font-weight:500;}
.weeklabel{
  min-height:48px;padding:0 16px;border-radius:var(--radius-md);color:var(--ink);
  transition:opacity .15s var(--ease),transform .15s var(--ease);
}
.weeklabel:active{opacity:.6;transform:scale(.97);}
.wkdots{display:flex;gap:3px;align-items:center;flex:0 0 auto;margin-right:4px;}
.wkdots .d{width:4px;height:4px;border-radius:50%;background:var(--green);}
.daystrip{
  display:flex;gap:6px;overflow-x:auto;padding:4px 2px 6px;
  scrollbar-width:none;-ms-overflow-style:none;
}
.daystrip::-webkit-scrollbar{display:none;}
.daypill{
  flex:1 1 0;min-width:42px;max-width:56px;min-height:60px;border-radius:var(--radius);
  background:var(--surface);box-shadow:var(--sh-1);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px;
  transition:background .15s var(--ease),transform .15s var(--ease);
  position:relative;
}
.daypill:active{transform:scale(.95);}
.daypill .dw{font-size:9.5px;font-weight:500;color:var(--grey);}
@media (max-width:374px){ .daystrip{gap:4px;} .daypill{min-width:40px;} }
.daypill .dn{font-size:var(--fs-h2);font-weight:600;font-variant-numeric:tabular-nums;}
.daypill .dot{width:4px;height:4px;border-radius:50%;background:var(--green);margin-top:2px;}
/* v1.6.5 block 0 (verification finding N1): selected day used --solid
   (ink), the v1.6 ruling calls for the accent token (--green, same
   token the mock's own .daypill.sel uses) -- ink read as an unrelated
   third colour next to the accent-toned dot/today states around it. */
.daypill.sel{background:var(--accent);border:1.5px solid var(--accent-edge);}
.daypill.sel .dw{color:var(--on-accent);}
.daypill.sel .dn{color:var(--on-accent);}
.daypill.sel .dot{background:var(--price-green);}
.daypill.today:not(.sel) .dn{color:var(--green);}
/* CB-14/16: advisory days (RDO, public holiday) carry a subtle tint and
   a text label whether selected or not, so the week reads at a glance
   without tapping each day — text, not colour alone, so it still reads
   in glare and for colourblind users. Advisory tone only, never warn:
   warn stays reserved for clashes and readiness flags. */
.daypill.holiday:not(.sel), .daypill.rdo:not(.sel){background:var(--fill);}
.daypill .phmark{font-size:var(--fs-eyebrow);font-weight:700;letter-spacing:.04em;color:var(--green);margin-top:1px;}
.daypill.sel .phmark{color:var(--on-accent);}

/* readiness ring */
.ring{width:40px;height:40px;flex:0 0 40px;}
.ring text{font-size:10.5px;font-weight:500;fill:var(--ink);font-variant-numeric:tabular-nums;}
.ring.done text{fill:var(--green);}
/* v1.7 block 8: Today's own ring stacks above the Today/Week toggle in
   one fixed-width right-hand column (not inline with either), so it
   never shrinks the heading's own title/sub block at 360px -- see
   todayHeadingHtml's own comment for why that matters (the j8 tab-bar
   collision). */
.todaystatecol{display:flex;flex-direction:column;align-items:flex-end;gap:6px;flex:0 0 auto;}
.todayworkring .ring{width:28px;height:28px;flex:0 0 28px;}
.todayworkring .ring text{font-size:11px;}

/* readiness pill */
.ready{font-size:var(--fs-fine);font-weight:500;color:var(--grey);white-space:nowrap;}
.ready.done{color:var(--green);}

/* list rows */
/* P item, the row primitive: .row, .assignrow, .jobrow and .checkwrap
   converge on one shape. All four already carried the 48 to 52px floor
   and a bottom divider, so this is the shared base declared once here;
   each keeps only its own further delta below (rule 11 -- nothing on
   any of the four is dropped). .checkwrap keeps align-items:stretch,
   its one real difference, so the tick button inside it still fills the
   row's own height rather than centering to its own content size. */
.row, .assignrow, .jobrow, .checkwrap{
  display:flex;align-items:center;gap:12px;min-height:48px;
  border-bottom:1px solid var(--hair);
}
.row{padding:8px 0;}
.row:last-child{border-bottom:none;}

/* checklist */
.checkwrap{align-items:stretch;padding:6px 0;}
span.ready.num{display:none;}
.checklist .checkwrap:last-child{border-bottom:none;}
/* Q87 (Chantelle phone review, 5 August 2026): the New Project readiness
   preview must not borrow .row/.checklist's own tappable shape -- that
   48px band plus hairline is visually identical to every real tickable
   list in the app, which is why it read as one. Deliberately inert: no
   min-height floor (not a tap target), a small leading dot rather than
   a checkbox-shaped edge, no per-row hairline suggesting more can be
   expanded or collapsed. */
.readinesspreview{padding:4px 2px;}
.readinesspreview .previewrow{display:flex;align-items:flex-start;gap:8px;padding:5px 0;}
.readinesspreview .previewdot{width:5px;height:5px;border-radius:50%;background:var(--faint);flex:0 0 5px;margin-top:7px;}
.check{display:flex;align-items:flex-start;gap:12px;min-height:52px;padding:10px 0;width:100%;text-align:left;}
.tick{
  width:26px;height:26px;flex:0 0 26px;border-radius:50%;margin-top:1px;
  border:1.5px solid var(--line);display:grid;place-items:center;
  transition:background .15s var(--ease),border-color .15s var(--ease);
}
.check.done .tick{background:var(--green);border-color:var(--green);}
.check .ct{font-size:13.5px;line-height:1.4;}
.check.done .ct{color:var(--grey);}
.check .stamp{font-size:var(--fs-fine);color:var(--grey);margin-top:1px;}
/* Deliveries run Phase 2 (13 August 2026): structured sub-fields under a
   checklist row's own title (Dispatch's Prepared/Scheduled items --
   stillages/contents, driver/address/when). Rendered as .checkwrap's own
   sibling, after the .check button, never inside it -- interactive
   content (an Add button, a driver select, a remove control) cannot
   nest inside .check without a button-inside-a-button. 38px = .tick's
   26px plus .check's own 12px gap, so the block's left edge lines up
   under the title text, not the tick. */
.checkfields{margin:2px 0 8px 38px;}
/* Deliveries run Phase 4 (13 August 2026): the delivery card, mock 17
   FINAL's own settled treatment -- white surface, standard shadow, a
   4px rail in the kind's own edge colour, a matching icon tile, one
   truck glyph (ICONS.delivery, already in the registry -- CLAUDE.md
   rule 14, no new icon needed) for both kinds. No border; text never
   sits on either fill (--dispatch/--supply), only the kind-coloured
   rail and the ink-toned glyph do, both measured to the 4.5:1 floor
   (:root's own comment on the six tokens). .dc is the full card
   (Schedule On site/Factory, Your day); .dpill is the compact row
   (Person sheet). Both real <button>s -- the base button{} reset
   (border:0, background:none) above already clears them for this. */
.dc,.dpill{--rail:var(--dispatch-edge);--tile:var(--dispatch);--glyph:var(--dispatch-ink);width:100%;}
.dc.in,.dpill.in{--rail:var(--supply-edge);--tile:var(--supply);--glyph:var(--supply-ink);}
.dc{
  background:var(--surface);box-shadow:var(--sh-1);border-radius:var(--radius);
  border-left:4px solid var(--rail);border-top-left-radius:6px;border-bottom-left-radius:6px;
  padding:11px 14px;margin-bottom:11px;display:flex;gap:12px;align-items:center;min-height:66px;
}
.dc .ico{width:38px;height:38px;flex:0 0 38px;border-radius:var(--radius-badge);background:var(--tile);display:grid;place-items:center;color:var(--glyph);}
.dc .ico svg{width:22px;height:22px;display:block;}
.dc .t{font-size:14.5px;font-weight:600;letter-spacing:-.01em;line-height:1.2;color:var(--ink);}
.dc .s{font-size:12px;color:var(--grey);margin-top:2px;}
.dc .go{margin-left:auto;color:var(--faint);flex:0 0 auto;}
.dc .go svg,.dpill .go svg{width:16px;height:16px;display:block;}
.dpill{
  display:flex;align-items:center;gap:10px;min-height:52px;padding:8px 12px;
  border-radius:var(--radius-md);background:var(--surface);box-shadow:var(--sh-1);
  border-left:4px solid var(--rail);border-top-left-radius:6px;border-bottom-left-radius:6px;margin-bottom:8px;
}
.dpill .ico{width:30px;height:30px;flex:0 0 30px;border-radius:9px;background:var(--tile);display:grid;place-items:center;color:var(--glyph);}
.dpill .ico svg{width:18px;height:18px;display:block;}
.dpill .tx{flex:1;min-width:0;}
.dpill .tx b{display:block;font-size:13px;font-weight:600;line-height:1.25;color:var(--ink);}
.dpill .tx small{display:block;font-size:11px;color:var(--grey);margin-top:1px;}
.dpill .go{color:var(--faint);font-size:15px;flex:0 0 auto;}
/* Week by project's own badge (Dispatch only -- decision: "a badge on
   its day"; Procurement is silent unless late). Small, inline, no fill/
   ink contrast question since it sits on the neutral --fill wash every
   other day-badge in that view already uses, tinted via the rail colour
   as a left accent only -- not a second place text sits on a fill. */
.dbadge{display:inline-flex;align-items:center;gap:4px;padding:2px 8px 2px 6px;border-radius:var(--radius-pill);background:var(--fill);border-left:3px solid var(--dispatch-edge);font-size:var(--fs-fine);color:var(--grey);}
.dbadge svg{width:12px;height:12px;flex:0 0 auto;}
/* Procurement's own late-only badge -- same tone-error idiom
   .typebadge.tone-error/.statbadge.tone-error already use (--fill plus
   --error ink), not a new colour pairing. */
.dbadge.warn{border-left-color:var(--error);color:var(--error);}
.check .rm{margin-left:auto;align-self:center;min-width:48px;min-height:48px;display:grid;place-items:center;color:var(--grey);font-size:var(--fs-fine);}
/* Q21 render-gate sweep: the base .rm rule "only ever existed inside
   .check" (see .alert .rm's own comment below) -- true, and every
   .checkwrap trailing pair (checkRowHtml's opts.trailing: dayprep edit/
   remove) and every custom trailing pair outside a .checkwrap entirely
   (project notes' pnote-edit/-remove) fell through it, rendering at the
   bare SVG icon's own ~16px width. An unscoped base rule fixes every
   .rm everywhere at once, rather than another one-off ancestor scope --
   the two rules below stay as harmless, more-specific duplicates. */
.rm{min-width:48px;min-height:48px;display:grid;place-items:center;color:var(--grey);}
/* Fast fix, 12 August 2026, pre-demo, retired by the task row rulings run
   (Phase 4, R3), same day: this hid taskRowHtml's own trailing edit pen
   by its action name, on the belief that the name was scoped to that one
   button. It wasn't -- data-action="dayprep-edit" is also
   taskDetailSheetBody's own "Edit details" overflow menu item, a
   different, legitimate control this rule was silently hiding too
   (measured directly: a Playwright click against it reported "element is
   not visible", 30s timeout, task-detail.spec.js's own "Edit details
   opens the full edit sheet" test). R3 retires the row's pen from the
   markup entirely now (taskRowHtml no longer renders it at all), so this
   rule's original target no longer exists to hide -- removed rather than
   left in place doing nothing for its own purpose while still breaking
   task detail's own Edit details. */
/* v1.8.1: a note-only task row (checkRowHtml's opts.noCheck) renders as
   a static div, not a button -- no tick to tap, so no pointer cursor. */
.check.noclick{cursor:default;}
/* align-self:center matches .taskbell's own pattern just below --
   .checkwrap's align-items:stretch otherwise stretches this to the
   full row height, turning border-radius:20px into a tall capsule. */
.notechip{display:inline-flex;align-items:center;align-self:center;gap:3px;font-size:var(--fs-fine);color:var(--grey);border:1px solid var(--line);border-radius:20px;padding:1px 8px 1px 6px;flex:0 0 auto;}
.notechip svg{width:12px;height:12px;}
/* Stage content v2, PHASE 4 (6 August 2026): the GATE marker -- decorative
   only (the accessible name is on the wrapping span itself via title/
   aria-label), same 12px sizing as .notechip's own icon. */
.gatemark{display:inline-flex;align-items:center;vertical-align:-2px;color:var(--grey);margin-right:2px;}
.gatemark svg{width:12px;height:12px;}
/* v1.8.3: the Tasks tab job chip -- tappable (unlike .notechip above,
   which is decorative only), so it carries the same 48px tap-target
   floor every other real control in this app holds (tap-targets.spec.js),
   not just .notechip's own compact sizing. */
.jobchip{
  display:inline-flex;align-items:center;align-self:center;
  min-width:48px;min-height:48px;padding:4px 12px;flex:0 0 auto;
  font-size:var(--fs-fine);font-weight:500;color:var(--ink);
  border:1px solid var(--line);border-radius:var(--radius-md);
  background:var(--fill);
  transition:opacity .15s var(--ease),transform .15s var(--ease);
  /* Run review redesign, 11 August 2026 (Chantelle, block 10 wins over
     the run review's own earlier ellipsis pass -- decision 181 amended):
     a long stage name wraps, it does not truncate. --radius-md rather
     than --radius-pill, since a pill reads as an egg once it wraps to
     more than one line; --radius-md reads as a rectangle at any height.
     max-width:100% still caps the chip at the row width, and
     .checkwrap.taskrow's own flex-wrap still lets a too-wide chip drop
     to its own line. */
  max-width:100%;
}
.jobchip .jobchiptxt{min-width:0;}
.jobchip:active{opacity:.6;transform:scale(.96);}

/* v1.7 block 2: tasks ride the same checklist row, amber rail + bell,
   per the Week/Projects mock -- "rendered from existing row
   components," not a new row shape. */
/* v1.8.3: flex-wrap:wrap only here, not on the shared .checkwrap rule
   above -- every other check-row surface (job checklist, project
   readiness, handover, take-to-site) only ever put narrow buttons
   (Edit/Remove) in trailing, which fit alongside the check button's own
   flex-shrink without needing to wrap. The Tasks tab's job chip is
   wide (a full job name), and .check's own width:100% left no room for
   it beside the check button -- it was rendering stacked on top of the
   row text instead of dropping to its own line. Scoped to .taskrow so
   nothing else's layout changes. */
/* v2.0 Brief 1B section 6.4: the always-on amber left rail ("orange dot"
   in the brief's own description) is gone -- state now lives on the
   avatar's own dot (.taskstatedot below), present only when there's
   actually something to flag (overdue), not on every row regardless of
   state. .check is a bare tick button now (no title/subline inside it
   any more -- both moved to the row's own text block), so its old
   flex:1 1 240px (room for a full-width row of text) is gone too. */
.checkwrap.taskrow{padding-left:0;flex-wrap:wrap;align-items:center;}
.checkwrap.taskrow .check{flex:0 0 auto;width:auto;min-width:48px;justify-content:center;padding:10px 4px;}
/* R3/R5 (task row rulings run, 12 August 2026): the row's own open
   control -- everything but the tick used to live inside a bare
   [data-action]-carrying <div> (mouse-tappable, never keyboard-reachable);
   .taskopen is the real <button> that replaces it, sized and positioned
   the same way the old .minw0.flex1 text column was. min-height matches
   .check's own 52px so the two controls line up; text-align:left and the
   button reset (styles.css ~261) keep it reading exactly like plain row
   content, not a boxed button. */
.checkwrap.taskrow .taskopen{display:flex;align-items:flex-start;gap:8px;flex:1 1 auto;min-width:0;width:auto;min-height:52px;padding:10px 0;text-align:left;}
.checkwrap.taskrow .taskopen .chevbox{align-self:center;flex:0 0 18px;}
.checkwrap.taskrow .jobchip{margin-top:4px;}
/* Run review, 11 August 2026 (Chantelle): measured at 360px, the row's
   text column was left 82px of 294 -- tick 48, avatar 18, pen 48, menu
   48 and four 12px gaps ate the rest, so every task title wrapped to
   three lines. Halving the column gap below 400px returns 24px to the
   text and costs nothing else; the four 48px targets are untouched.
   This is density relief, not the fix: the row carries five elements at
   360px and wants a decision on which of them earns its place. */
@media (max-width:400px){
  .checkwrap.taskrow{column-gap:6px;}
}
/* Defects run 7 Aug, Phase 5 (measured defect): the stage sheet's own
   Open tasks list only (opts.compact) -- nine rows measured at ~150px
   each, driven by a wrapping title's own line-height plus the subtitle
   and stamp lines stacking under it, never by the tick (already at the
   48px floor and untouched here). Tightens the text stack only. */
/* line-height on .ct itself measured zero effect (its wrapped text's line
   boxes are governed by the containing block, not the inline span) --
   confirmed by testing both directly against the live DOM before landing
   this on .minw0.flex1 instead, which measured a real reduction. */
.checkwrap.taskrow.compact .minw0.flex1{line-height:1.15;}
/* R2 (task row rulings run, 12 August 2026) moved the subtitle line off a
   bare .fine.mt-2 onto .taskmeta (see below) -- this compact-density rule
   re-targeted to match, or the stage sheet's own compact Open tasks list
   would silently stop getting the tightened spacing it was written for. */
.checkwrap.taskrow.compact .taskmeta{margin-top:1px;}
.checkwrap.taskrow.compact .stamp{margin-top:0;}
.taskavatarwrap{position:relative;flex:0 0 auto;align-self:center;margin-right:2px;}
.taskstatedot{
  position:absolute;bottom:-1px;right:-1px;width:10px;height:10px;border-radius:50%;
  background:var(--warn);border:2px solid var(--surface);
}
/* R2 (task row rulings run, 12 August 2026): avatars move off the task
   row's leading edge onto this meta line, right-aligned and spaced, not
   overlapping -- mock 18b option A. min-height:22px keeps a row with
   faces and a row without the same height, so a list of mixed assigned/
   unassigned tasks still lines up. The text side wraps rather than
   truncates (no nowrap/ellipsis) so "Overdue, wants attention" can read
   in full per R5/mock 18 -- the four-face-plus-long-stage-name case is
   the one this is expected to grow the row for, not hide text from. */
.checkwrap.taskrow .taskmeta{display:flex;align-items:flex-start;gap:8px;min-height:22px;margin-top:2px;}
.checkwrap.taskrow .taskmeta .taskmetatext{flex:1 1 auto;min-width:0;}
/* .onmeta overrides the base .taskavatarwrap's leading-edge margin (2px
   right, centered) with a right-pinned one -- margin-left:auto keeps the
   cluster at the same right edge on every row regardless of how long the
   stage/status text before it runs (the mock's option A, not option B's
   "trails the text directly", which was rejected for moving row to row). */
.checkwrap.taskrow .taskmeta .taskavatarwrap.onmeta{align-self:flex-start;margin-left:auto;margin-right:0;flex:0 0 auto;}
/* Spaced, not overlapping -- the shipped cluster's own -6px overlap
   (.assigneecluster .avatar, styles.css ~591) is a density trick for six
   or eight faces in a tight space; scoped out here since a cap of four on
   a whole meta line doesn't need it and it costs legibility at 20px. 20px
   down from the cluster's own 18px small size, since avatars no longer
   lead the row and can afford the whole meta line's own vertical room. */
.checkwrap.taskrow .taskmeta .onmeta .assigneecluster{margin-left:0;gap:4px;}
.checkwrap.taskrow .taskmeta .onmeta .assigneecluster .avatar{margin-left:0;box-shadow:none;}
.checkwrap.taskrow .taskmeta .onmeta .avatar{width:20px;height:20px;flex-basis:20px;font-size:9.5px;}

/* v2.6 (Chantelle, 6 August): bottom nav rebuilt wordless -- four glyphs
   and a docked "+", five slots. Ported from
   claude_fen_taska_mock_week_by_people_v2_6aug.html's own .nav/.navbtn/
   .navadd/.navdot block, retokenised onto this app's own variables
   (--tabbar-bg not the mock's bare --surface, --accent-tint not a new
   green-soft/green-ink pair -- same tint the old .tab.active already
   used, so the "on" treatment stays visually continuous with the shape
   it replaces) rather than copied byte-for-byte.
   The one condition on a wordless bar, not negotiable: the current tab
   carries three signals together -- .navbtn.on's filled pill, its own
   heavier glyph stroke, and aria-current="page" (render.js). Removing
   any one is a change to this ruling, not a tidy-up. */
.nav{
  position:fixed;bottom:0;left:50%;transform:translateX(-50%);
  width:100%;max-width:560px;z-index:40;
  display:grid;grid-template-columns:repeat(5,1fr);align-items:center;
  background:var(--tabbar-bg);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  border-top:1px solid var(--hair);box-shadow:0 -6px 18px rgba(var(--ink-rgb),.06);
  padding:6px 8px calc(6px + env(safe-area-inset-bottom));
}
.navbtn{
  display:grid;place-items:center;min-height:48px;min-width:48px;width:100%;
  border-radius:var(--radius-pill);color:var(--grey);background:none;border:0;
  position:relative;justify-self:center;transition:background .15s var(--ease),color .15s var(--ease);
}
.navbtn svg{width:24px;height:24px;display:block;}
.navbtn:active{opacity:.7;}
.navbtn.on{background:var(--accent-tint);color:var(--ink);}
.navbtn.on svg{stroke-width:2.1;}
.navdot{
  position:absolute;top:9px;right:calc(50% - 15px);width:8px;height:8px;
  border-radius:50%;background:var(--warn);border:2px solid var(--tabbar-bg);
}
/* an empty grid cell, same width as a real slot, so the four real
   .navbtn's stay evenly spaced either side of .navadd below even though
   .navadd itself is not a DOM child of this grid (see its own comment,
   render.js navAddBtnHtml). */
.navaddslot{width:100%;min-height:48px;}
/* the plus is the FAB, docked -- an action, not a tab, so none of the
   three current-tab signals apply and it is never aria-current.
   Independently fixed-positioned (not a .nav child) so it keeps the
   pre-v2.6 .fab's own reach-through-an-open-sheet behaviour below;
   centred to land exactly over .nav's own empty middle slot. */
.navadd{
  position:fixed;z-index:41;left:50%;transform:translateX(-50%);
  bottom:calc(16px + env(safe-area-inset-bottom));
  width:56px;height:56px;border-radius:50%;
  outline:5px solid var(--tabbar-bg);
  background:var(--accent);color:var(--on-accent);border:1.5px solid var(--accent-edge);
  display:grid;place-items:center;box-shadow:var(--sh-2);
  transition:transform .15s var(--ease);
}
.navadd svg{width:26px;height:26px;display:block;}
.navadd:active{transform:translateX(-50%) scale(.96);}
/* v1.8.1: the crew add-menu needs to work from inside an open job sheet
   ("if the crew is inside a job-day when they tap"), but .backdrop/
   .sheet sit at z-index 50/51, above .navadd's own 41 -- without this
   the button is simply unreachable behind an open sheet. Scoped to the
   crew data-action only; leadership's Quick actions FAB is unchanged,
   matching the original v1.8.1 ruling ("leadership sees no change from
   this pass") this override has carried since before the nav rebuild.
   v2.6 fix: further scoped to .reach (render.js's own
   reachThroughJobSheet, true only while a job sheet specifically is
   open) -- the centred dock position otherwise put this override on top
   of the add flow's own follow-on sheets, stealing taps meant for them. */
.navadd[data-action="crew-add-open"].reach{z-index:52;}
/* v2.6: replaces .view.has-fab's padding-bottom -- the add button is
   now a permanent bar slot, not a conditionally-floating circle, so
   every signed-in view reserves the same fixed space, always. */
.padnav{height:86px;}

/* bottom sheets */
.backdrop{
  position:fixed;inset:0;z-index:50;background:rgba(var(--ink-rgb),.38);
  opacity:0;transition:opacity .2s var(--ease);
  pointer-events:none;touch-action:none;
}
.backdrop.show{opacity:1;pointer-events:auto;}
.sheet{
  position:fixed;bottom:0;left:50%;transform:translate(-50%,100%);
  width:100%;max-width:680px;z-index:51;
  background:var(--surface);border-radius:var(--radius-sheet) var(--radius-sheet) 0 0;
  max-height:86vh;display:flex;flex-direction:column;
  transition:transform .2s var(--ease);
  box-shadow:var(--sh-lift);
}
.sheet.show{transform:translate(-50%,0);}
/* v1.6 block 10: 48px minimum (logged since v1.4) -- the visible bar
   stays a slim 4px, but the tappable/draggable area around it grows to
   the floor via min-height, not a taller-looking handle. */
.sheet-grab{flex:0 0 auto;min-height:48px;padding:10px 0 4px;display:grid;place-items:center;touch-action:none;cursor:grab;}
.sheet-grab .bar{width:36px;height:4px;border-radius:2px;background:var(--hair);}
.sheet-body{flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;padding:6px 20px calc(24px + env(safe-area-inset-bottom));-webkit-overflow-scrolling:touch;}
/* the new-job wizard keeps Next/Back/Add job in a sticky footer, so a long
   crew list on step 2 never buries the primary action */
.sheet-body.has-foot{padding-bottom:14px;}
.sheet-foot{
  flex:0 0 auto;padding:12px 20px calc(14px + env(safe-area-inset-bottom));
  border-top:1px solid var(--hair);background:var(--surface);
}
/* Add project Phase 1, "one exit": a sticky title row carrying the close,
   so a long sheet has one explicit, always-visible way out rather than
   only the drag handle and backdrop. Negative margin cancels .sheet-body's
   own 20px side padding so the bar's background bleeds edge to edge under
   it, matching .sheet-body's -6px top padding so it sits flush at scroll 0. */
.shbar{
  position:sticky;top:-6px;z-index:5;
  display:flex;align-items:center;gap:8px;
  margin:-6px -20px 0;padding:6px 20px 10px;
  background:var(--surface);border-bottom:1px solid var(--hair);
}
.shbar .sht{flex:1;min-width:0;font-size:15px;font-weight:600;color:var(--ink);}
/* Add project Phase 3 (decision 182): the mode line replacing the 50/50
   segmented control -- one quiet statement plus a Change button, mock 15
   v3's own .modeline/.modebtn names. min-height:48px on the button holds
   the tap floor without visually growing past its text. */
.modeline{display:flex;align-items:center;gap:8px;min-height:48px;}
.modeline .ml{flex:1;min-width:0;font-size:13px;color:var(--grey);}
.modeline .ml b{color:var(--ink);font-weight:600;}
.modebtn{min-height:48px;padding:0 12px;font-size:13px;font-weight:600;color:var(--green-ink);border-radius:var(--radius-md);}
.modebtn:active{background:var(--fill);}
/* Add project Phase 4: the real stage preview under the project type
   dropdown, mock 15 v3's own .prevcard/.prevnames names. .track/.pip are
   shipped already (programme strip). */
.prevcard{background:var(--fill);border-radius:var(--radius-md);padding:11px 12px;}
.prevcard .track{margin-bottom:8px;}
.prevnames{font-size:11.5px;color:var(--grey);line-height:1.5;}
.prevnames b{color:var(--ink);font-weight:600;}
.stepind{
  font-size:var(--fs-eyebrow);font-weight:500;
  color:var(--grey);text-align:center;margin:0;
}

/* profile picker */
.picker{
  position:fixed;inset:0;z-index:60;background:var(--page-light);
  display:flex;flex-direction:column;align-items:center;overflow-y:auto;
  padding:8vh 22px calc(28px + env(safe-area-inset-bottom));
}
.picker .plist{width:100%;max-width:420px;margin-top:26px;}
.prow{
  display:flex;align-items:center;gap:14px;width:100%;text-align:left;
  background:var(--surface);border:1px solid var(--hair);border-radius:var(--radius);
  padding:12px 14px;margin-bottom:10px;min-height:64px;
  transition:transform .15s var(--ease),opacity .15s var(--ease);
}
.prow:active{transform:scale(.98);opacity:.85;}
.prow .pn{font-size:15px;font-weight:500;}
.prow .pt{font-size:12px;color:var(--grey);}

/* v1.6 block 5: stat tiles, rebuilt to mock semantics -- label above the
   number, an icon badge, "X of Y" denominators. .stats is a two-column
   grid (two rows of two at 360px), not one row of four: the four-across
   row is what pushed a crew chip under the fixed tab bar in the v1.4
   attempt at wide tracking everywhere (see tap-targets.spec.js's
   chip/tab-bar sweep, and docs/fen_taska_v1_4_gap_register.md G3). The
   badge sits absolutely positioned so label/number keep a plain block
   flow underneath it, same layout idea as the mock. */
/* v1.7 block 8: margin-bottom 6px, not 10px -- part of the named
   j8/tab-bar 8px clearance fix on Schedule Today at 360x800. */
.stats{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin:6px;}
.stat{
  position:relative;background:var(--surface);box-shadow:var(--sh-1);
  border-radius:var(--radius);padding:8px 12px;text-align:left;min-height:48px;
  transition:transform .15s var(--ease),opacity .15s var(--ease);
}
.stat:active{transform:scale(.97);opacity:.75;}
/* P item (Tile primitive): label now sits below the number in the
   markup (render.js:645 statTileHtml), so no CSS reordering is needed
   here -- flow follows DOM order. Number grows 20 to 30px per the same
   ruling. */
.stat .eyebrow{display:block;margin-top:2px;}
.stat .statn{
  display:block;font-size:30px;font-weight:600;
  font-variant-numeric:tabular-nums;letter-spacing:-0.01em;
}
.stat .statn small{font-size:var(--fs-fine);font-weight:500;color:var(--grey);margin-left:3px;}
/* Q70 (5 August 2026): the delta chip, coloured by the caller's own
   tone -- what the metric means, never the arithmetic sign of the
   value itself. tone-warn/tone-accent reuse the same ink colours as
   .statbadge's own tone map, one level lighter in weight than the
   number beside it. */
.stat .statdelta{font-size:12px;font-weight:700;margin-left:4px;font-variant-numeric:tabular-nums;}
.stat .statdelta.tone-warn{color:var(--warn-ink);}
.stat .statdelta.tone-accent{color:var(--green);}
.stat .statdelta.tone-neutral{color:var(--grey);}
.stat .statdelta.tone-error{color:var(--error);}
.statbadge{
  position:absolute;top:8px;right:8px;width:28px;height:28px;border-radius:var(--radius-badge);
  display:grid;place-items:center;flex:0 0 auto;
}
.statbadge svg{width:14px;height:14px;}
/* one accent, plus the functional warn/error pair the direction doc
   allows (amber for flags, red for no-crew/destructive) -- block 10
   split --warn into its own amber/red tokens (tone-warn/tone-error
   below now read the two separately). */
.statbadge.tone-accent{background:var(--fill);color:var(--green);}
.statbadge.tone-neutral{background:var(--fill);color:var(--grey);}
.statbadge.tone-warn{background:var(--fill);color:var(--warn-ink);}
.statbadge.tone-error{background:var(--fill);color:var(--error);}
/* D7, P item (Tile primitive delta): .covercell deleted -- 22
   declarations (this block plus the .covercell.today .cl rule that sat
   below .pstat), zero call sites, confirmed by grep across render.js,
   app.js, data.js and index.html. Dead code, not retreated. */

/* v1.7 block 8: the Projects card's three-stat row -- readiness,
   today's work, next -- replacing the old rollup sentence. Same compact
   label-over-value idea, three even columns. */
.projstats{display:flex;gap:6px;margin-top:8px;}
.pstat{flex:1;min-width:0;}
.pstat .pl{font-size:9px;font-weight:500;color:var(--grey);margin-bottom:2px;}
.pstat .pv{font-size:var(--fs-body);font-weight:600;font-variant-numeric:tabular-nums;}
.pstat .pv.warn{color:var(--warn-ink);}

/* alerts -- v1.6 block 8: one card per alert (mock), severity carried by
   the leading badge's icon shape as well as its colour, not a dot alone.
   16px titles, uppercase meta. */
.alert{display:flex;gap:12px;align-items:flex-start;min-height:48px;}
/* v1.4 block 11: a linked alert is a real button (opens what it's
   about), everything else about its layout stays identical to the
   plain-text row -- reset the button defaults, keep the same box. */
button.alert{width:100%;text-align:left;background:var(--surface);font:inherit;}
button.alert:active{opacity:.6;}
.alertbadge{width:38px;height:38px;flex:0 0 38px;border-radius:var(--radius-badge);display:grid;place-items:center;margin-top:1px;}
.alertbadge.tone-warn{background:var(--fill);color:var(--warn-ink);}
.alertbadge.tone-info{background:var(--fill);color:var(--green);}
/* v1.8 amendment section 11.2/11.5: the flag rollup badge -- an amber
   circle, the existing --warn token, no new colour. Same shape on a
   project card and the Projects tab total (.lg, a touch bigger since it
   sits alone in the header rather than beside a project name). */
.flagbadge{
  min-width:26px;height:26px;padding:0 7px;border-radius:50%;flex:0 0 auto;
  display:grid;place-items:center;background:var(--warn);color:var(--on-semantic);
  font-size:var(--fs-fine);font-weight:600;margin:2px 8px 0 0;
}
/* v2.0 Brief 1B section 6.1: on the Projects tab card specifically, the
   spec (v1.8 §11.2) wants a small circle pinned top-right of the card,
   not sitting in the .projhead flex column's own stacking order (where
   it rendered on its own full-width row between the title and toggle --
   .projhead is flex-direction:column with the default align-items:
   stretch, never overridden, so this child's width stretched to fill
   the column's cross axis, the full-width amber ellipse bug). Absolute,
   scoped to this one context only -- .flagbadge itself stays untouched
   for its other uses (the project sheet's own flags list, the Projects
   tab flag total, Schedule Week's flagchip). */
.projcard{position:relative;}
.projhead .flagbadge{position:absolute;top:12px;right:15px;margin:0;}
.flagbadge.lg{min-width:32px;height:32px;font-size:var(--fs-body);}
/* v1.8 amendment section 12.8: typed attention chips on a Schedule Week
   job row -- small inline badges, one per attention type, ordered by
   the caller (jobAttentionChipsHtml). Amber family throughout, no new
   colour; flagchip reuses the flagbadge circle at a smaller size. */
.attnchips{display:inline-flex;gap:4px;margin-left:6px;vertical-align:middle;}
.attnchip{
  display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 5px;
  border-radius:var(--radius-pill);font-size:10px;font-weight:700;line-height:1;
}
.attnchip.flagchip{background:var(--warn);color:var(--on-semantic);}
.attnchip.overduechip{background:var(--warn);color:var(--on-semantic);}
.attnchip.railchip{background:var(--fill);color:var(--warn-ink);}
.attnchip.pendingchip{background:var(--fill);color:var(--grey);}
/* v1.8 amendment section 13.1: the quick-add chip strip -- horizontal
   scroll, not wrap, so a long discipline library never pushes the
   freeform input far down the sheet. */
.chiprow.scrollx{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:2px;}
.chiprow.scrollx .taketchip{flex:0 0 auto;}
.chiprow.scrollx .typechip{flex:0 0 auto;}
.alert .at{font-size:16px;font-weight:500;line-height:1.35;display:block;}
.alert.read .at{color:var(--grey);}
.alert .am{font-size:10px;font-weight:600;color:var(--grey);margin-top:3px;display:block;}
/* v2.0 Brief 1B section 7.1: the swipe-to-dismiss trash icon, same
   48px-floor sizing as every other .rm use, scoped here since the base
   .rm rule only ever existed inside .check. */
.alert .rm{flex:0 0 auto;align-self:center;min-width:48px;min-height:48px;display:grid;place-items:center;color:var(--grey);}
/* sticky "Clear all" / "Show read" action bar above the alerts feed. */
.alertsbar{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  position:sticky;top:0;z-index:3;background:var(--page-light);
  padding:8px 0;margin-bottom:4px;
}

/* misc */
.divider{height:1px;background:var(--hair);margin:16px 0;}
.empty{color:var(--grey);font-size:var(--fs-sub);padding:10px 0;}
.maplink{display:inline-flex;align-items:center;gap:8px;font-size:13.5px;font-weight:500;color:var(--green);text-decoration:underline;text-underline-offset:2px;min-height:48px;}
.maplink svg{width:16px;height:10px;flex:0 0 16px;}
.maplink svg.pin{width:14px;height:14px;flex:0 0 14px;}
/* v1.8 amendment section 10.1: the drawings chip rides the same row as
   the address, same visual weight -- a flex row, wrapping on narrow
   viewports rather than the drawings chip ever squeezing the address. */
.addressrow{display:flex;flex-wrap:wrap;align-items:center;column-gap:18px;}
/* section 10.3: the subdued "Add drawings link" state -- not a broken
   link (no underline), a quiet dashed affordance, same family as
   attributeChipHtml's own "+ Accom" dashed convention. */
.maplink.subdued{
  color:var(--grey);text-decoration:none;border:1px dashed var(--hair);
  border-radius:var(--radius-pill);padding:0 10px;min-height:48px;background:none;
}
.maplink.subdued svg{opacity:.6;}
.warncard{border-color:var(--hair);}
.warntext{color:var(--warn-ink);font-size:12px;font-weight:500;}
/* Stage catch-up run, 7 Aug 2026, Phase 1: the gate card. Same warn-tone
   convention as .exi.warn/.needs below (--fill plus --warn-ink) rather
   than the mock's own dedicated --warn-soft token, which doesn't exist
   here. */
.gatecard{margin-top:10px;background:var(--fill);border-radius:var(--radius-md);padding:12px 14px;}
.gatecard .gh{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:600;color:var(--warn-ink);}
.gatecard .gh svg{width:16px;height:16px;display:block;flex:none;}
.gatecard p{font-size:12.5px;line-height:1.5;color:var(--warn-ink);margin:6px 0 0;}
/* v2.6 (Chantelle, 6 August): "Needs you," Schedule Today's exception
   list. Markup ported from mock 02/04a's own .needs/.ex/.exi/.ext, but
   the tone backgrounds reuse this app's existing soft-tone convention
   (--fill plus a coloured icon/text, same as .typebadge.tone-error)
   rather than the mock's own dedicated --error-soft/--warn-soft tokens,
   which don't exist here. .needs itself rides on the shared .card class
   in markup (background/radius/shadow), not redefined. */
.needs-head{display:flex;align-items:baseline;gap:8px;padding:2px 0 8px;}
.needs-head b{font-size:15px;font-weight:600;}
.needs-head span{margin-left:auto;font-size:13px;color:var(--grey);}
.ex{
  display:flex;align-items:center;gap:11px;width:100%;min-height:48px;padding:11px 0;
  border:0;border-top:1px solid var(--hair);background:none;text-align:left;color:var(--ink);
}
.ex:active{background:var(--press-bg);}
.exi{width:28px;height:28px;border-radius:var(--radius-md);flex:none;display:grid;place-items:center;}
.exi svg{width:15px;height:15px;display:block;}
.exi.bad{background:var(--fill);color:var(--error);}
.exi.warn{background:var(--fill);color:var(--warn-ink);}
.ext{flex:1;min-width:0;font-size:13px;}
.ext b{display:block;font-size:14px;font-weight:600;line-height:1.35;}
.ext span{color:var(--grey);font-size:12px;}
.ex .chev{width:16px;height:16px;color:var(--faint);flex:none;}
/* Deliveries run Phase 4 (13 August 2026): Needs you's one exception
   row with two actions instead of one -- "Chased today"/"Open order",
   matching the mock's own two-chip row (mock 17 FINAL's .needs). Every
   other .ex row here is a single button with one destination; this one
   is a plain (non-button) row wrapping onto a second line for its own
   pair of real .chip buttons, indented to align under the title text
   the same way Dispatch's own .checkfields does. */
.exorder{align-items:flex-start;flex-wrap:wrap;}
.exchips{flex:0 0 100%;display:flex;gap:8px;margin:8px 0 0 39px;}
/* Materials run, PHASE 2 (9 August 2026, decision 147): the register
   row's own status tag. Everything else on the row rides the existing
   .card/.cardrow/.sub scaffolding (variationsFoldHtml/projectPlantFoldHtml
   above) -- this is the one genuinely new piece, same --fill-plus-
   coloured-text convention as .exi/.gatecard above rather than a fourth
   soft-tone token set. Only "used" gets a tone: "coming up" and
   "unallocated" are both plain, since neither is a judgement this model
   can back yet (that's Phase 4's lead-time exception, not this tag). */
.mtag{display:inline-flex;align-items:center;flex:none;background:var(--fill);color:var(--grey);font-size:11px;font-weight:600;padding:3px 9px;border-radius:var(--radius-pill);white-space:nowrap;}
.mtag.used{color:var(--green);}
.needs .more{
  display:flex;align-items:center;justify-content:center;gap:6px;width:100%;min-height:48px;
  border:0;border-top:1px solid var(--hair);background:none;font-size:13px;font-weight:500;color:var(--grey);
}
.needs .more svg{width:16px;height:16px;display:block;}
/* Shape run, 7 Aug 2026, Phase 1: the programme strip -- mock 02 v2's
   pip-per-stage summary, replacing the grey chip wall on the Projects
   tab card and project detail. .strip itself rides on .card in markup
   (background/radius/shadow), same convention .needs above already
   established. */
.strip{margin-top:6px;}
.track{display:flex;align-items:center;gap:4px;}
/* Demo polish run, 11 Aug 2026, Phase 2: flex:1 with no cap let a 1- or
   2-stage project's pip(s) stretch edge to edge (measured 266px/131px at
   360px), reading as a placeholder that failed to load rather than a
   programme. A max-width caps growth so the track runs short instead --
   32px sits just above the 23-31px a 5+ stage project already measures,
   so that case is unaffected. */
.pip{height:7px;border-radius:4px;flex:1;max-width:32px;background:var(--hair);}
.pip.done{background:var(--green);}
.pip.live{background:var(--fill);box-shadow:inset 0 0 0 1.5px var(--green);}
.pip.planned{background:none;border:1px dashed var(--faint);}
.stripnow{margin:9px 0 0;font-size:13px;}
.stripnow b{font-weight:600;}
.stripnow span{color:var(--grey);}
.addrow{display:flex;gap:8px;margin-top:10px;}
.addrow input{
  flex:1;min-width:0;min-height:48px;border:1px solid var(--hair);border-radius:var(--radius-md);padding:0 14px;
  font-size:var(--fs-h2);background:var(--page-light);outline:none;
}
/* Q103: the crew day sheet's own "+" on Taking to site -- a flex row so
   the accordion toggle and the add button are two real sibling buttons
   (a <button> cannot nest another), plus the two-row inline choice and
   its two mini-forms. */
.sechrow{display:flex;align-items:center;gap:4px;}
.sechrow .accbtn{flex:1;}
.addbtn{
  width:48px;height:48px;flex:0 0 48px;display:grid;place-items:center;
  border-radius:var(--radius-pill);background:var(--fill);color:var(--green);
  font-size:20px;font-weight:600;line-height:1;
}
.inlinechoice{background:var(--fill);border-radius:var(--radius-md);padding:2px 10px;margin:6px 0 10px;}
.choicerow{width:100%;text-align:left;}
/* base .ct/.stamp: the crew day sheet's take/day-work rows sit directly
   under .checkwrap (styled there already); the choice row above has no
   .check ancestor to inherit from, so this gives it the same look. */
.ct{font-size:13.5px;line-height:1.4;}
.stamp{font-size:var(--fs-fine);color:var(--grey);margin-top:1px;display:block;}
.addrow input:focus{border-color:var(--grey);}
.ghostchip{position:fixed;z-index:70;pointer-events:none;opacity:.92;transform:translate(-50%,-50%) scale(1.05) rotate(3deg);box-shadow:var(--sh-2);}
body.dragging, body.dragging *{user-select:none;-webkit-user-select:none;}
.droptarget{border-color:var(--green) !important;box-shadow:0 0 0 1px var(--green);}
.board-job.droptarget{transform:translateY(-2px);}
.chip{-webkit-touch-callout:none;}
.chip.dragsrc{opacity:.35;}
/* v1.6 block 8: mock row anatomy -- 49px rows (the .assignrowbtn child
   below keeps its own explicit 48px floor regardless, so this is only
   the declared minimum, not a cap: real rows with two lines of content
   still grow past it). */
.assignrow{width:100%;text-align:left;padding:8px 0;}
.assignrow:last-child{border-bottom:none;}
.assignrow .an{font-size:var(--fs-body);font-weight:500;}
.assignrow .as{font-size:11.5px;color:var(--grey);}
.assignrow .aw{font-size:var(--fs-fine);color:var(--warn-ink);font-weight:500;}
/* D22 (Q69, 5 August 2026): .leadtag deleted -- its only call site
   (assignRowsHtml) dropped the "Job lead" text caption, the hard hat
   toggle beside the row now carries the meaning alone. */
.assignrow .tick{margin-left:auto;flex:0 0 26px;margin-top:0;align-self:center;}
.assignrow.on .tick{background:var(--green);border-color:var(--green);}
/* v1.4 block 3 (D2): the row itself is a div now, not a button, so the
   hard hat can sit beside the name as its own sibling control instead of
   nesting a button inside a button. .assignrowbtn carries the row's own
   look (a plain reset here; .assignrow above already supplies the
   flex/height/divider) and covers everything except the hat. */
/* v1.5 final adversarial pass: align-items:center on .assignrow (not
   stretch) means this button never filled the row's own 56px -- it sized
   to its two lines of content instead, ~42px, under the 48px floor. The
   row visually read as tall enough; the actual tap target wasn't. */
.assignrowbtn{display:flex;align-items:center;gap:12px;flex:1;min-width:0;min-height:48px;text-align:left;background:none;border:none;padding:0;font:inherit;color:inherit;}
.hardhat{width:48px;height:48px;flex:0 0 48px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:none;border:none;color:var(--grey);margin-left:4px;}
/* v1.6 block 8: mock's tinted-circle active hat, not a plain colour swap */
.hardhat.on{color:var(--green);background:var(--fill);}
/* toast: quiet confirmation with undo, sits clear above the FAB band
   so its live Undo button never sits over the + button */
.toast{
  position:fixed;left:50%;bottom:calc(148px + env(safe-area-inset-bottom));z-index:80;
  transform:translate(-50%,16px);opacity:0;
  display:flex;align-items:center;gap:6px;
  /* Morning run, 12 August 2026, Phase 7 (measured defect): width:auto on a
     fixed+flex box with a wrapping text child shrunk to the width of its
     longest word (~148px), not to the available space -- .tmsg's own
     nowrap+ellipsis was papering over that by never letting the text wrap
     in the first place, which is what actually truncated "<name> added.
     Add a stage to get it on the board." at 300px against 354/478px
     needed. width:max-content sizes the toast to its own single-line
     content when nothing needs to wrap (every short toast, unchanged,
     still reads as a compact pill) and to its wrap width when something
     does; max-width stays the outer safety cap for a narrow viewport. */
  width:max-content;max-width:calc(100% - 36px);
  background:var(--solid);color:var(--on-solid);border-radius:var(--radius-md);padding:11px 8px 11px 16px;
  font-size:var(--fs-sub);line-height:1.4;
  box-shadow:var(--sh-2);
  transition:opacity .2s var(--ease),transform .2s var(--ease);
}
.toast.show{opacity:1;transform:translate(-50%,0);}
.toast .tmsg{flex:0 1 260px;min-width:0;overflow-wrap:break-word;}
/* Tier 1 celebration moments: same non-blocking toast positioning, no
   action button so it's never interactive, capped at 1200ms by JS */
.celebrate-toast{padding:8px 16px 8px 10px;}
.celebrate-toast .ctart{flex:0 0 auto;width:30px;height:30px;display:grid;place-items:center;color:var(--price-green);}
.celebrate-toast .ctart ft-stage{display:block;}
/* v1.4 block 7: the job sheet's persistent "marked done" state -- the
   kit's stage="done" drawing, held still, in a sage wrapper per the
   kit README. Low-opacity sage fill (not a token yet; block 8 formalises
   the token layer this and every other one-off colour value moves onto). */
.donewrap{
  display:flex;flex-direction:column;align-items:center;text-align:center;gap:6px;
  margin-top:10px;padding:18px 14px;border-radius:var(--radius);
  background:rgba(var(--green-rgb),.12);color:var(--green);
}
/* a flex column with align-items:center sizes children to their own
   intrinsic width, and the kit's svg only ever resolves width as a
   percentage of its ancestor chain -- with nothing upstream giving it a
   real pixel value, that chain collapses to 0 and the drawing renders
   with no visible area at all. An explicit width breaks the cycle,
   same reason the celebration toast's own wrapper (.ctart) fixes both
   dimensions instead of just height. */
.donewrap ft-stage{display:block;width:160px;}
.toast button{
  color:var(--price-green);font-size:var(--fs-sub);font-weight:600;
  min-height:48px;min-width:48px;padding:0 10px;margin:-13px 0;flex:0 0 auto;
}

/* leadership quick actions: the "+" sheet contents (the button itself
   is .navadd, styles.css "bottom nav" block above) */
.qrow{
  display:flex;align-items:center;gap:14px;width:100%;text-align:left;
  min-height:64px;padding:10px 0;border-bottom:1px solid var(--hair);
  transition:opacity .15s var(--ease),transform .15s var(--ease);
}
.qrow:last-child{border-bottom:none;}
.qrow:active{opacity:.7;transform:scale(.99);}
.qrow .qi{width:40px;height:40px;flex:0 0 40px;border-radius:var(--radius-md);background:var(--fill);color:var(--green);display:grid;place-items:center;}
.qrow .qi svg{width:20px;height:20px;}
.qrow .qn{font-size:14.5px;font-weight:500;}
.qrow .qs{font-size:12px;color:var(--grey);}
/* D1 (treatment v2.4): 12.5px sentence case, not 10px uppercase --
   larger, quieter and easier to read. 116 call sites, the largest single
   group in the sweep. */
.fieldlab{font-size:12.5px;font-weight:500;color:var(--grey);margin:14px 0 6px;}
.fieldinput{
  width:100%;min-height:48px;border:1px solid var(--hair);border-radius:var(--radius-md);
  padding:0 14px;font-size:var(--fs-h2);background:var(--page-light);outline:none;color:var(--ink);
}
textarea.fieldinput{padding:12px 14px;min-height:76px;resize:vertical;line-height:1.45;}
.fieldinput:focus{border-color:var(--grey);}
/* Deliveries run Phase 3 (13 August 2026): the order/docket paste area
   -- same dashed-box idiom as .addbucket's own affordance styling
   (line 566-ish, a different control), real tokens rather than the
   mock's own hardcoded #fcfcfb/#cfd2cf. */
.paste{min-height:70px;border:1.5px dashed var(--line);border-radius:var(--radius-md);padding:11px 12px;font-size:12.5px;color:var(--faint);line-height:1.6;background:var(--fill);resize:vertical;width:100%;font-family:inherit;}
.paste:focus{outline:none;border-color:var(--grey);color:var(--ink);}
/* Deliveries run Phase 3: Log a delivery's own pre-filled quantity row
   -- description/outstanding on the left, an editable number on the
   right. A real 48px control, not a bare native number spinner sized
   to its digits. */
.led{display:flex;align-items:center;gap:10px;min-height:48px;border-bottom:1px solid var(--hair);}
.led:last-child{border-bottom:none;}
.led .nm{flex:1;font-size:13px;line-height:1.35;}
.led .nm small{display:block;font-size:var(--fs-fine);color:var(--grey);margin-top:1px;}
.qtyinput{width:64px;min-height:48px;border:1px solid var(--hair);border-radius:var(--radius-md);text-align:center;font-size:var(--fs-h2);background:var(--page-light);color:var(--ink);}
.qtyinput:focus{outline:none;border-color:var(--grey);}
/* Projects walkthrough fixes run, 11 Aug 2026, Phase 6 (decision 195):
   a native <select> still drew its OS-default arrow, never matching
   the app's own .car chevron mark. CSS only -- appearance:none plus a
   background-image chevron in the same stroke language as ICONS.chev
   (1.9 stroke, round caps/joins), since a <select> doesn't reliably
   render ::after content to composite the real .car glyph over it.
   Colour is the light --faint hex baked into the SVG (data: URIs can't
   read custom properties); the dark-theme rule below re-embeds the
   dark --faint hex so both themes still match their own token exactly,
   not just a fixed neutral guess. */
select.fieldinput{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  padding-right:40px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239a9ea4' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;background-size:18px;
}
[data-theme="dark"] select.fieldinput{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236d7178' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}
.btn:disabled{opacity:.45;pointer-events:none;}
/* Permissions run (6 Aug 2026), Phase 4: see .iconbtn.muted's own
   comment above -- same boundary look, pointer events and press state
   both left live. */
.btn.muted{opacity:.45;}
.chevbox{width:18px;height:18px;flex:0 0 18px;color:var(--faint);}
/* v1.3.1 item 10: My Week's collapsed/expanded day toggle — a separate
   modifier, not the base .chevbox rule, which stays a plain forward-
   pointing chevron everywhere else it's already used (My hours, quick
   assign) */
.chevbox.toggle{transform:rotate(90deg);transition:transform .15s var(--ease);}
.chevbox.toggle.open{transform:rotate(-90deg);}
.chevbox svg{width:18px;height:18px;display:block;}

/* job depth: tappable My Week entries, contact phone links,
   checklist day chips. Same palette, no new colours. */
.mwjob{cursor:pointer;border-radius:10px;transition:opacity .15s var(--ease),transform .15s var(--ease);}
.mwjob:active{opacity:.7;transform:scale(.99);}
.tel{
  margin-left:auto;display:inline-flex;align-items:center;gap:7px;
  min-height:48px;padding:0 2px;flex:0 0 auto;
  font-size:13.5px;font-weight:500;color:var(--ink);text-decoration:none;white-space:nowrap;
  transition:opacity .15s var(--ease),transform .15s var(--ease);
}
.tel svg{color:var(--green);flex:0 0 15px;}
.tel:active{opacity:.6;transform:scale(.97);}
/* Contacts run B, 11 Aug 2026, Phase 2: the edit card, mock 15 v3.
   Namespaced cx*, grepped clean against every existing rule first --
   .cxff must never also carry .tel, which is the shipped phone-LINK
   rule (margin-left:auto, flex:0 0 auto) and silently shrank/pushed a
   field right the one time an earlier draft collided with it.
   .cxcard bounds one contact's fields as a single card -- addressing
   the pre-existing defect where nothing bounded a contact and a
   flowed label ("Contact 2 role") was the only thing saying whose
   field was whose. */
.cxcard{background:var(--surface);border-radius:var(--radius);box-shadow:var(--sh-2);padding:12px 14px 14px;margin:10px 0;}
/* Phase 4: the card header carrying the live name/role preview and
   the remove action -- .rm is the shipped 48x48 remove-button rule
   (styles.css, "the base .rm rule"), reused rather than redrawn. */
.cxhead{display:flex;align-items:center;gap:10px;min-height:34px;margin-bottom:6px;}
.cxhead .cxt{flex:1;min-width:0;font-size:14px;font-weight:600;color:var(--ink);line-height:1.2;}
.cxhead .cxs{display:block;font-size:11.5px;font-weight:400;color:var(--grey);margin-top:2px;}
.cxgrid{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
.cxgrid .span2{grid-column:1 / -1;}
.cxff{position:relative;}
.cxff input{width:100%;height:58px;padding:22px 14px 6px;border:1px solid var(--hair);border-radius:var(--radius-md);background:var(--fill);color:var(--ink);font-size:15px;font-family:var(--font);outline:none;transition:border-color .15s var(--ease),background .15s var(--ease);}
.cxff label{position:absolute;left:15px;top:18px;font-size:15px;color:var(--faint);pointer-events:none;transition:all .15s var(--ease);}
.cxff input:focus{border-color:var(--accent-edge);background:var(--surface);}
.cxff input:focus + label,
.cxff input:not(:placeholder-shown) + label{top:8px;font-size:10.5px;font-weight:500;letter-spacing:.02em;color:var(--grey);}
.cxff.cxtel input{font-variant-numeric:tabular-nums;padding-right:58px;}
/* ring the number without leaving the form -- rendered only when
   there is something to ring; the input keeps the caret, this takes
   the tap. */
.cxcall{position:absolute;right:5px;top:5px;width:48px;height:48px;display:grid;place-items:center;border-radius:var(--radius-md);color:var(--green-ink);background:var(--surface);}
.cxcall svg{width:19px;height:19px;display:block;}
.cxcall:active{opacity:.6;}
/* Contacts run B, Phase 3: the revealed email field gets a quiet accent
   border so the reveal itself reads as something that just happened. */
.cxff.on input{border-color:var(--accent-edge);background:var(--surface);}
/* the add-an-email ghost cell: an envelope carrying a plus, gone once
   the field it reveals has a value and the sheet/page next opens fresh. */
.cxghost{display:flex;align-items:center;justify-content:flex-start;gap:10px;width:100%;height:48px;padding:0 14px;border:1px dashed var(--line);border-radius:var(--radius-md);background:none;color:var(--green-ink);font-size:13px;font-weight:500;transition:background .15s var(--ease),border-color .15s var(--ease);}
.cxghost:active{background:var(--fill);border-style:solid;}
.cxghost .cxenv{position:relative;width:22px;height:22px;flex:0 0 22px;display:grid;place-items:center;}
.cxghost .cxenv svg{width:19px;height:19px;}
.cxghost .cxpl{position:absolute;right:-4px;bottom:-3px;width:13px;height:13px;border-radius:50%;background:var(--accent);border:1.5px solid var(--surface);color:var(--on-accent);display:grid;place-items:center;font-size:10px;font-weight:700;line-height:1;}
/* Contacts run B, Phase 5 (rulings section 2 items 6-7): the saved
   contact -- identity row plus one tappable value line per value that
   exists. Applies wherever contacts render, project page and stage
   sheet alike (Phase 6). */
.cxsum{padding:10px 0;border-bottom:1px solid var(--hair);}
.cxsum:last-of-type{border-bottom:0;}
.cxid{display:flex;align-items:center;gap:12px;min-height:48px;}
.cxn{display:block;font-size:15px;font-weight:500;color:var(--ink);line-height:1.25;}
.cxrole{display:block;font-size:12px;color:var(--grey);margin-top:1px;}
.cxlines{margin-top:6px;border-radius:var(--radius-md);overflow:hidden;background:var(--fill);}
.cxlinerow{display:flex;align-items:center;border-top:1px solid var(--surface);}
.cxlinerow:first-child{border-top:0;}
.cxline{display:flex;align-items:center;gap:10px;flex:1;min-width:0;min-height:48px;padding:0 4px 0 12px;text-decoration:none;color:var(--ink);}
.cxline:active{opacity:.6;}
.cxline .cxg{width:17px;height:17px;flex:0 0 17px;color:var(--green-ink);display:block;}
/* wraps, per CLAUDE.md's own "this codebase wraps, it does not
   truncate" (decision 181) -- deliberately not the mock's own
   text-overflow:ellipsis, which can clip at any text-size step. */
.cxline .cxval{flex:1;min-width:0;font-size:14px;overflow-wrap:anywhere;}
.cxcopy{width:48px;height:48px;flex:0 0 48px;display:grid;place-items:center;color:var(--faint);}
.cxcopy svg{width:16px;height:16px;}
/* Contacts run B, Phase 7 (rulings section 3): reuse a contact already
   on file against the builder. */
.cxsuggwrap{background:var(--surface);border-radius:var(--radius-md);box-shadow:var(--sh-1);padding:2px 4px;margin-top:8px;}
.cxsugg{display:flex;align-items:center;gap:10px;width:100%;min-height:56px;padding:6px 8px;background:none;border:0;border-top:1px solid var(--hair);text-align:left;}
.cxsugg:first-of-type{border-top:0;}
.cxsugg:active{background:var(--press-bg);}
.cxsugg.taken{opacity:.5;}
.cxaddmark{width:32px;height:32px;flex:0 0 32px;border-radius:50%;background:var(--fill);color:var(--green-ink);display:grid;place-items:center;font-size:18px;font-weight:600;line-height:1;}
.cxaddmark.done{background:var(--accent);color:var(--on-accent);border:1.5px solid var(--accent-edge);font-size:0;}
.cxaddmark.done svg{width:14px;height:14px;}
.daychip{
  display:inline-block;margin-left:8px;padding:2px 8px;border-radius:var(--radius-pill);
  background:var(--fill);color:var(--green);
  font-size:var(--fs-eyebrow);font-weight:500;vertical-align:1px;
}
.daybtn{
  align-self:center;min-width:48px;min-height:48px;flex:0 0 auto;
  font-size:var(--fs-eyebrow);font-weight:500;
  color:var(--faint);border-radius:10px;
  transition:opacity .15s var(--ease),transform .15s var(--ease),background .15s var(--ease);
}
.daybtn.set{color:var(--green);background:var(--fill);}
.daybtn:active{opacity:.6;transform:scale(.95);}
/* R block 3: derived project stage chips. Never colour alone — every chip
   carries its status as text, not just a background tint. */
.stagechips{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0 0;}
.stagechip{
  display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border-radius:var(--radius-pill);
  background:var(--fill);color:var(--grey);font-size:var(--fs-fine);font-weight:600;
}
.stagechip .scs{font-weight:500;opacity:.85;}
/* Q81 (5 August 2026): a bare accent fill, found without its
   --accent-edge border during this ruling's own verification pass. */
.stagechip.st-now{background:var(--accent);color:var(--on-accent);border:1.5px solid var(--accent-edge);}
.stagechip.st-behind{background:var(--warn);color:var(--on-semantic);}
/* Defects run 7 Aug, Phase 7: the priority chip, same tone as taskRowHtml's
   own (its own inline padding/margin predates rule 13's gate and is left
   as-is) -- this modifier gives taskDetailSheetBody the same compact
   shape without a new inline style. */
.stagechip.pri{padding:1px 6px;margin-left:4px;}
/* v1.3.1 item 3: the project-sheet chip is a real sign-off toggle for
   leadership; the project-card chip stays a plain non-interactive span.
   v1.6.5 block 8: a "behind" chip is tappable everywhere (a <span
   role="button">, not a <button> -- two of stageChipsHtml's own call
   sites already nest inside another real button, see its own comment),
   so this is keyed off data-action rather than the button tag. */
/* Q21 render-gate sweep: the interactive sign-off/reveal variant measured
   under the 48px floor (a slim text pill, no min-height) -- the read-only
   card copy (a plain span, never interactive) is untouched, so it stays
   the compact pill it always was. */
button.stagechip, .stagechip[data-action]{border:none;cursor:pointer;min-height:48px;transition:opacity .15s var(--ease),transform .15s var(--ease);}
button.stagechip:active, .stagechip[data-action]:active{opacity:.7;transform:scale(.97);}
.stagechip.st-done{color:var(--faint);text-decoration:line-through;}
/* motion spec tier 2: stage chips fade in, 150ms */
@keyframes chipfadein{from{opacity:0;}to{opacity:1;}}
.stagechip{animation:chipfadein .15s var(--ease);}

/* ----------------------------------------------------------------
   Project page run, 10 August 2026, Phase 3 (decision 168, mock 14).
   Stage rows: the project page's Stages fold, one hairline row per
   stage in place of the previous card-per-stage, which read as tall
   and mostly empty at desktop width. Number chip, name, progress in
   trade words, dates right, chevron. Tone follows stageLifecycleState
   (app.js) directly -- done/now/up are this component's own names for
   'complete'/'live'/everything else, not a fourth status source.
   ---------------------------------------------------------------- */
.stgrow{
  display:flex;align-items:center;gap:12px;width:100%;min-height:56px;
  padding:10px 2px;border-bottom:1px solid var(--hair);text-align:left;
  background:none;border-left:0;border-right:0;border-top:0;
  transition:background .15s var(--ease);
}
.stglist .stgrow:last-of-type{border-bottom:0;}
.stgrow:active{background:var(--press-bg);}
.stgnum{
  width:26px;height:26px;flex:0 0 26px;border-radius:8px;
  display:grid;place-items:center;font-size:12px;font-weight:600;
  background:var(--cream);color:var(--grey);
}
.stgrow.done .stgnum{background:var(--fill);color:var(--green-ink);}
.stgrow.now .stgnum{background:var(--accent);color:var(--on-accent);border:1.5px solid var(--accent-edge);}
.stgbody{flex:1;min-width:0;}
.stgname{display:block;font-size:15px;font-weight:600;line-height:1.3;}
.stgrow.done .stgname,.stgrow.up .stgname{font-weight:500;}
.stgrow.done .stgname{color:var(--grey);}
.stgmeta{display:block;font-size:12px;color:var(--grey);margin-top:2px;}
.stgside{flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;gap:2px;text-align:right;}
.stgdates{font-size:var(--fs-fine);color:var(--grey);white-space:nowrap;}
.stgrow .car{width:15px;height:15px;flex:0 0 15px;color:var(--faint);}
.nowtag{display:inline-block;margin-left:8px;padding:2px 8px;border-radius:var(--radius-pill);
  background:var(--fill);color:var(--green-ink);font-size:var(--fs-eyebrow);font-weight:600;vertical-align:1px;}
/* Project page run, 10 August 2026, Phase 7 (measured defect, CLAUDE.md
   rule 5): ICONS.plant has no width/height attributes of its own (it
   inherits ICONS' shared viewBox-only shape), so dropped straight inside
   an .h2 span it renders at its unconstrained block size -- screenshotted
   on the stage sheet's new Plant on this stage fold, a crane glyph nearly
   filling the sheet. .plicon sizes it the way .avatar already sizes
   ICONS.plant at resourceRowsHtml's own call site (render.js).*/
.plicon{display:inline-grid;place-items:center;width:28px;height:28px;flex:0 0 28px;
  border-radius:var(--radius-badge);background:var(--fill);color:var(--grey);
  vertical-align:-8px;margin-right:8px;}
.plicon svg{width:15px;height:15px;}

/* the done-stages fold: one summary row for every complete stage, the
   mock 13 rule (decision 163) applied at row scale -- filled means
   closed, flat means open. */
.donefoldbtn{background:var(--surface);border-radius:var(--radius-badge);
  box-shadow:var(--sh-1);padding:10px 12px;margin:2px 0 8px;border-bottom:0;
  display:flex;align-items:center;gap:12px;width:100%;min-height:56px;text-align:left;}
.donefoldbtn.open{background:none;box-shadow:none;border-radius:0;
  padding:10px 2px;margin:0;border-bottom:1px solid var(--hair);}
.donetick{background:var(--fill);color:var(--green-ink);}
.donefoldbtn .foldcar{transform:rotate(90deg);transition:transform .18s var(--ease);}
.donefoldbtn.open .foldcar{transform:rotate(-90deg);}
.donefoldbody .stgrow{padding-left:10px;}

/* ----------------------------------------------------------------
   Project page run, 10 August 2026, Phase 4 (decision 169). The
   "Running alongside" side column's own heading -- unconditional, since
   .maincol/.sidecol are plain stacking wrappers below 1000px, no CSS of
   their own to gate. */
.sidehead{display:flex;align-items:center;min-height:48px;padding:6px 0;
  font-size:15px;font-weight:600;color:var(--ink);}
.sidehead b{flex:1;min-width:0;font-weight:600;}
/* v1.6 block 6: Schedule Week's expanded job row (mock: .jrow) -- one
   dense line per job, days and crew as text in the subline, readiness
   right-aligned, a coloured left rail carrying job type/status. Sits
   inside a group's .accinner (unstyled wrapper), so the row itself
   supplies its own padding and divider, same pattern as .assignrow. */
.jobrow{
  width:100%;text-align:left;padding:10px 14px;
  border-left:3px solid var(--green);background:none;
  transition:opacity .15s var(--ease);
}
/* Run review redesign, 11 August 2026 (Chantelle, block 10 wins --
   decision 181 amended): the stage lens names the project on the row
   (weekJobRowHtml's own opts.showProject), but the heading wraps rather
   than ellipsising -- block 10's zero-truncation rule stands. No CSS
   rule is needed here any more: weekJobRowHtml itself now sources
   rowProjName from the project's own short name (no builder suffix),
   which is what actually overflowed a single line, so the heading fits
   without a wrap in practice and never needs one in principle. Do not
   re-add a .jobrow.withproj .h2 truncation rule -- fix overflow at the
   source (the string), not at the render (an ellipsis). */
.jobrow:last-child{border-bottom:none;}
.jobrow:active{opacity:.7;}
.jobrow.rail-ins{border-left-color:var(--grey);}
/* v1.6 block 10: no crew is the "no-crew" case the DoD reserves --error
   (red) for, not --warn (amber, flags/clashes) */
.jobrow.rail-none{border-left-color:var(--error);}
/* P item (Rail primitive): the sage type rail above is kept as shipped;
   this is the new half -- an amber attention rail, for a row that wants
   a look without being the no-crew/gap error case. Defined here,
   available to whichever row needs it; wiring it into a specific
   surface's markup is surface-pass work. */
.jobrow.rail-attn{border-left-color:var(--warn);}
.jobrowrt{font-size:var(--fs-fine);font-weight:600;color:var(--grey);flex:0 0 auto;text-align:right;line-height:1.3;}
.jobrowrt b{display:block;font-size:var(--fs-sub);line-height:1.15;}
.jobrowrt.bad{color:var(--error);}
/* v1.7 block 7: Schedule Week's coverage rail -- one dot per visible
   day, solid green (crewed), red outline (scheduled with nobody, the
   actual gap), or empty fill (not scheduled). .gap on the row itself
   (not .rail-none, which meant "nobody at all") covers a job with at
   least one uncovered scheduled day, per the mock. */
.jobrow.gap{border-left-color:var(--error);}
.covdots{display:flex;gap:3px;margin-top:3px;}
.covdot{width:14px;height:14px;border-radius:4px;background:var(--fill);display:grid;place-items:center;font-size:7.5px;font-weight:600;color:var(--faint);}
.covdot.on{background:var(--green);color:var(--on-solid);}
.covdot.bad{background:transparent;border:1.5px solid var(--error);color:var(--error);}
/* v2.6: the person lens's fourth dot state -- a day off someone's own
   pattern (not in workingDays, an industry RDO, or approved leave) is
   dashed, never red. Getting this wrong paints a person's whole week
   red on their days off, the same bug the run doc calls out for stages. */
.covdot.off{background:transparent;border:1.5px dashed var(--hair);color:var(--faint);}

/* view entry transition, applied only on tab change */
@keyframes viewin{from{opacity:0;transform:translateY(5px);}to{opacity:1;transform:none;}}
.view.anim{animation:viewin .18s var(--ease);}
/* motion spec tier 2: day card list staggers in on view entry only */
@keyframes cardstagger{from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:none;}}
.card.stagger{animation:cardstagger .2s var(--ease) both;}
/* motion spec tier 2: Board's Today/Week-by-project toggle slides
   horizontally in the direction of travel, 200ms */
@keyframes boardslidefwd{from{opacity:0;transform:translateX(16px);}to{opacity:1;transform:none;}}
@keyframes boardslideback{from{opacity:0;transform:translateX(-16px);}to{opacity:1;transform:none;}}
.boardslide-fwd{animation:boardslidefwd .2s var(--ease);}
.boardslide-back{animation:boardslideback .2s var(--ease);}

@media (min-width:700px){
  .view{padding-left:24px;padding-right:24px;}
}
/* desktop grace: wider shell, two column card grids, centred tabs */
@media (min-width:1000px){
  #app{max-width:1040px;}
  .view{padding-left:32px;padding-right:32px;}
  .cards{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-items:stretch;margin-bottom:12px;}
  .cards .card{margin-bottom:0;}
  /* Projects tab: always a single-column stack, at any width. A 2-up
     grid here would let an expanded card's sibling sit beside it in the
     same row instead of the expanded panel pushing later cards down. */
  .cards.projstack{display:block;}
  .cards.projstack .card{margin-bottom:12px;}
  /* Demo batch run, 10 Aug 2026, Phase 4: a lone card in the 2-up grid
     above sat in the first column only, leaving the second column empty
     -- measured on the Tasks tab, the general case (any .cards with
     exactly one .card child, checked against every other call site --
     Schedule Today's Office bucket has the same single-card shape and
     the same defect; Factory/On site/My Week/day-summary sheets carry 2+
     cards in normal use and are unaffected since :only-child never
     matches there). Projects' own .projstack override above solves a
     different problem (an expanded card's sibling sitting beside it) and
     is untouched. */
  .cards > .card:only-child{grid-column:1 / -1;}
  .viewhead{margin-top:16px;}
  .weeknav{max-width:470px;}
  /* Project page run, 10 August 2026, Phase 4 (decision 169): the stat
     strip goes four across at this width only -- two 490px tiles per row
     inside the widened #app is the same tall-empty problem the stage
     cards had, mobile is untouched (.stats' own base rule, above). */
  .stats{grid-template-columns:repeat(4,1fr);}
  /* the project page's own two-column body: programme left, a sticky
     Running alongside column right. DOM order (maincol then sidecol)
     puts the side column after the programme content, so below this
     width, with no grid applied, it simply stacks under the programme --
     nothing about the markup itself depends on this width. */
  .pagegrid{display:grid;grid-template-columns:1fr 340px;gap:0 28px;align-items:start;}
  .sidecol{position:sticky;top:64px;max-height:calc(100vh - 80px);overflow-y:auto;
    scrollbar-width:none;padding-bottom:12px;}
  .sidecol::-webkit-scrollbar{display:none;}
}
/* ---- delight pass: quick, green-and-ink only, all guarded by
   prefers-reduced-motion at the bottom of this block ---- */

/* checklist tick: spring scale on the circle, the white stroke sweeps in */
@keyframes tickspring{0%{transform:scale(.7);}55%{transform:scale(1.12);}100%{transform:scale(1);}}
@keyframes tickdraw{from{stroke-dashoffset:23;}to{stroke-dashoffset:0;}}
.check.done.just .tick{animation:tickspring .25s var(--ease);}
/* dashoffset:23 (hidden) comes only from the animation's own 0% keyframe,
   never as a static value here -- under prefers-reduced-motion the
   animation is killed globally (see the reduced-motion block below) and
   stroke-dashoffset falls back to its initial value of 0, i.e. fully
   drawn, rather than freezing invisible mid-stroke. */
.check.done.just .tick svg path{stroke-dasharray:23;animation:tickdraw .2s .05s var(--ease) forwards;}
@keyframes stampfadein{from{opacity:0;}to{opacity:1;}}
.check.done.just .stamp{animation:stampfadein .2s .15s var(--ease) both;}

/* hard hat: pops in when it takes the lead (not on every render, only the
   toggle that actually set it -- same .just transient-flag pattern as the
   tick above, cleared right after render so it never replays) */
@keyframes hatpop{0%{transform:scale(.6);}65%{transform:scale(1.15);}100%{transform:scale(1);}}
.hardhat.on.just{animation:hatpop .3s var(--ease);}

/* readiness hits 100: one quiet pop on the job card, Ready settles in.
   v1.6 block 8: was a box-shadow ring pulse -- motion spec is transform/
   opacity only, so this is a brief scale pop instead of a glow. */
@keyframes readypulse{0%{transform:scale(1);}40%{transform:scale(1.015);}100%{transform:scale(1);}}
.card.celebrate{animation:readypulse .5s var(--ease) 1;}
@keyframes readyin{from{opacity:0;transform:translateY(3px);}to{opacity:1;transform:none;}}
.celebrate .ready.done{animation:readyin .25s var(--ease) both;}
@keyframes ringpop{0%{transform:scale(1);}45%{transform:scale(1.07);}100%{transform:scale(1);}}
.ring.celebrate{animation:ringpop .45s var(--ease);}

/* drag and drop: dropped chip snaps then settles */
@keyframes chipsettle{0%{transform:scale(1.1);}60%{transform:scale(.98);}100%{transform:scale(1);}}
.chip.settle{animation:chipsettle .25s var(--ease);}

/* alerts: badge pops in, bell gives one small nudge on a new unread.
   v1.6 block 8: the infinite pulse this used to also carry (softpulse,
   a box-shadow ring, matching the alert dot's own pulse) is gone -- a
   persistent badge looping motion forever with no user action is the
   exact thing the brief's motion ruling flags. The one-shot pop-in
   still says "this just changed" without running indefinitely. */
@keyframes badgepop{0%{transform:scale(0);}70%{transform:scale(1.18);}100%{transform:scale(1);}}
.navbtn .navdot.pop{animation:badgepop .25s var(--ease);}
@keyframes bellnudge{0%,100%{transform:rotate(0);}30%{transform:rotate(8deg);}65%{transform:rotate(-6deg);}}
.navbtn svg.nudge{animation:bellnudge .3s var(--ease) 1;}

/* press states on everything tappable: scale plus a light shade */
.assignrow,.check,.rm,.maplink{transition:transform .15s var(--ease),background .15s var(--ease),opacity .15s var(--ease);}
.assignrow:active,.check:active{transform:scale(.97);background:var(--fill);border-radius:var(--radius-md);}
.rm:active,.maplink:active{transform:scale(.97);opacity:.65;}
.card.press:active{background:var(--press-bg);}
.daypill:active{background:var(--fill);}
.daypill.sel:active{background:var(--accent);}

/* day strip: gentle snap scrolling on narrow screens */
.daystrip{scroll-snap-type:x proximity;}
.daypill{scroll-snap-align:start;}

/* bottom sheet opens with a light spring; close stays quick */
.sheet.show{transition:transform .3s cubic-bezier(.28,1.18,.36,1);}

/* toast never blocks taps to the board behind it; only Undo is live */
.toast{pointer-events:none;}
.toast button{pointer-events:auto;}
.toast .tsep{color:var(--on-dark-muted);flex:0 0 auto;}

/* empty states: one human line with a quiet leaves accent, never behind data */
.emptystate{padding:22px 4px 16px;color:var(--grey);font-size:var(--fs-sub);display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center;}

/* sign-in by phone: 16px+ input so mobile browsers never zoom, tel keypad */
.signinwrap{width:100%;max-width:420px;margin-top:20px;}
.signinwrap input{
  width:100%;min-height:52px;border:1px solid var(--hair);border-radius:var(--radius);
  padding:0 16px;font-size:17px;background:var(--surface);outline:none;color:var(--ink);
  font-variant-numeric:tabular-nums;letter-spacing:.02em;
}
.signinwrap input:focus{border-color:var(--grey);}
.signinmsg{font-size:12.5px;font-weight:500;color:var(--warn-ink);min-height:18px;margin:8px 2px 0;}
.signinnote{font-size:var(--fs-fine);color:var(--grey);margin:12px 2px 0;text-align:center;}
.demotoggle{
  display:inline-flex;align-items:center;gap:6px;min-height:48px;margin-top:14px;
  font-size:12.5px;font-weight:500;color:var(--grey);
  transition:opacity .15s var(--ease);
}
.demotoggle:active{opacity:.6;}
.demotoggle .caret{display:inline-flex;color:var(--faint);}
.demotoggle .caret svg{width:11px;height:11px;display:block;}

/* segmented picker for team and role: same ink-selected language as day pills */
.segrow{display:flex;gap:8px;}
/* G defect 2: no min-width, so a narrow context (e.g. the Tasks status
   filter's two-word segments) shrank this under the 48px floor on its
   narrow axis -- measured 38.9x48 at 360px. tap-targets.spec.js now
   sweeps both axes here, not just height. */
.segrow .segbtn{
  flex:1;min-width:48px;min-height:48px;border-radius:var(--radius-md);border:1px solid var(--hair);background:var(--surface);
  font-size:var(--fs-sub);font-weight:500;color:var(--grey);
  transition:background .15s var(--ease),color .15s var(--ease),transform .15s var(--ease);
}
.segrow .segbtn:active{transform:scale(.97);}
.segrow .segbtn.on{background:var(--solid);border-color:var(--solid);color:var(--on-solid);}

/* v1.6.5 block 1 (decision D2, option B): the compact pill toggle used
   for Schedule Today/Week and the Week group-by control. Distinct from
   segrow above (which Team's scope/scan controls keep, out of scope for
   this pass) -- inactive segments show icon only, the active segment
   reveals icon plus its word via a width/opacity transform, never a
   colour-only change. */
/* Decision 197 (11 August 2026): the container was --fill, a green-grey
   almost identical to the page it sits on -- every toggle dissolved
   into the background instead of reading as a control. --acc-row
   (decision 163, styles.css:2130-2131) already resolves to --surface
   at root and --page-light inside .sheet/.card/.groupcard, so reusing
   it here means a toggle sitting on a white card still contrasts,
   the same reasoning that token pair was built for, not a new one. */
.pilltoggle{display:inline-flex;flex:0 0 auto;background:var(--acc-row);border:1px solid var(--hair);border-radius:999px;padding:4px;gap:2px;}
.pillseg{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:48px;min-width:48px;padding:0 13px;border:none;border-radius:999px;
  background:none;color:var(--grey);font-size:var(--fs-sub);font-weight:500;font-family:inherit;
  transition:background .15s var(--ease),color .15s var(--ease),transform .15s var(--ease);
}
.pillseg svg{width:20px;height:20px;flex:0 0 20px;display:block;}
.pillseg span{max-width:0;overflow:hidden;opacity:0;white-space:nowrap;transition:max-width .15s var(--ease),opacity .1s var(--ease);}
.pillseg.on{background:var(--solid);color:var(--on-solid);}
/* Decision 197: a .typechip (base style: --surface fill, --hair border,
   styles.css:1959) cannot stay white once its own container just
   became opaque -- Open/Done (below) moves onto this component as a
   pair of .typechip, not .pillseg, since both states carry a full
   word at all times and .pillseg only ever shows a word on the
   selected segment. Unselected only: .on keeps the existing ink fill
   and white text unchanged, same rule as every other typechip. */
.pilltoggle .typechip:not(.on){background:none;border:none;}
/* v1.7 block 9: 80px comfortably fit every label this component carried
   before Team's own pairs joined it (Today/Week/Project/Location, all
   8 characters or under); "My discipline"/"Whole company" (13 each)
   clipped invisibly against that ceiling -- no test caught it (the
   clipping sweep only flags text-overflow:ellipsis, and this used plain
   overflow:hidden), found on sight in the closing screenshot pass.
   150px comfortably clears the longest label with room to spare. */
.pillseg.on span{max-width:150px;opacity:1;}
.pillseg:active{transform:scale(.96);}

/* Project catch-up run, 7 August 2026, Phase 4: the project's five-week
   schedule horizon. Colours are all existing tokens, none of them new
   literals (CLAUDE.md rule 13's own colour-literal gate) -- stage reads in
   --green (the programme strip's own "live" colour family), material a
   solid --ink dot, plant --grey, tentative an open --faint ring rather
   than a fill, since it hasn't happened yet. */
.wkgrp{margin-bottom:14px;}
.wkgrp:last-child{margin-bottom:0;}
.wkgrph{font-size:var(--fs-sub);color:var(--grey);margin-bottom:2px;}
.wkgrph b{color:var(--ink);font-weight:600;}
.quietwk{font-size:var(--fs-sub);color:var(--faint);padding:6px 0 12px;margin:0;}
.ev{display:flex;align-items:center;gap:10px;width:100%;min-height:48px;padding:6px 2px;text-align:left;background:none;border:none;border-bottom:1px solid var(--hair);}
.ev:last-child{border-bottom:none;}
.evd{flex:0 0 auto;width:44px;font-size:12px;font-weight:600;color:var(--grey);font-variant-numeric:tabular-nums;}
.evb{flex:0 0 auto;width:10px;height:10px;border-radius:50%;background:var(--grey);}
.evb.k-stage{background:var(--green);}
.evb.k-material{background:var(--ink);}
.evb.k-plant{background:var(--grey);}
.evb.k-plan{background:none;border:1.5px solid var(--faint);}
.evt{flex:1 1 auto;min-width:0;font-size:var(--fs-body);color:var(--ink);}
.evt span{display:block;font-size:12px;color:var(--grey);margin-top:1px;}
.evkey{display:flex;flex-wrap:wrap;gap:8px 16px;margin:12px 0 4px;font-size:12px;color:var(--grey);}
.evkey div{display:flex;align-items:center;gap:5px;}
.mhead{margin-bottom:8px;}
.mhead b{font-size:var(--fs-body);font-weight:600;color:var(--ink);}
.dow{display:grid;grid-template-columns:repeat(7,1fr);text-align:center;font-size:11px;color:var(--faint);margin-bottom:4px;}
/* No data-action anywhere in .calgrid, on purpose -- 360px / 7 columns
   measures under the 48px tap floor, so this grid is never a control
   (Phase 5 proves it with a measured interactive-element count of zero
   on this surface). */
.calgrid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;margin-bottom:8px;}
.calgrid span{display:flex;align-items:center;justify-content:center;aspect-ratio:1;font-size:12px;color:var(--ink);position:relative;}
.calgrid span.out{color:transparent;}
.calgrid span.today{font-weight:700;box-shadow:inset 0 0 0 1.5px var(--ink);border-radius:50%;}
.calgrid span[data-k]::after{content:'';position:absolute;bottom:2px;width:5px;height:5px;border-radius:50%;background:var(--green);}
.calgrid span[data-k="material"]::after{background:var(--ink);}
.calgrid span[data-k="plant"]::after{background:var(--grey);}
.calgrid span[data-k="plan"]::after{background:none;border:1px solid var(--faint);}
.calnote{font-size:12px;color:var(--faint);margin:0 0 10px;}

/* v1.6.5 block 1: the heading row a toggle joins -- heading block on
   the left, the pill toggle right-aligned, both top-aligned so a
   two-line heading doesn't centre the toggle awkwardly against it. */
.headrow{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;}
/* Run review, 11 August 2026 (Chantelle): .todaystatecol is a fixed
   208px, so on a 360px screen the date block was left with 108px.
   "Monday 10" wrapped to two lines and the summary sentence to four,
   and the header ran 199px tall against 158px at 430px. Below 400px the
   controls drop to their own full-width line under the date instead of
   competing with it. Scoped to .viewhead so no other .headrow moves. */
@media (max-width:400px){
  .viewhead .headrow{flex-wrap:wrap;}
  /* laid out as a wrapping row, not a column, so the work ring pairs with
     the Today/Week toggle on one line instead of sitting alone as a bare
     "0", and the header costs two lines rather than three. */
  .viewhead .headrow > .todaystatecol{width:100%;flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:flex-start;gap:8px;}
}
.title.fs-24{font-size:calc(24px * var(--text-scale));}

/* archived people: present but quiet. The archflag badge marks anyone
   archived while still resolving on a roster; neutral grey, not the
   warn tone, because it is a state, not a conflict. */
.chip.arch{opacity:.55;}
.chip .flag.archflag{color:var(--grey);}
/* v1.6 block 7: RDO/away moved off the chip and onto a once-per-day line
   (see dayAdviceHtml) -- the only remaining .flag.awayflag is My Week's
   own day header (the signed-in person's own leave, once on their day),
   not a chip, so this is unscoped now rather than .chip-prefixed. */
.flag.awayflag{color:var(--warn-ink);}
/* v1.3.1 item 13: the job lead's chip carries its own border plus a text
   badge -- readable without relying on colour to tell it apart from the
   rest of the rostered crew. */
.chip.lead{border-color:var(--green);border-width:1.5px;}
.chip .flag.leadflag{color:var(--green);display:inline-flex;align-items:center;gap:2px;}
/* Q102 (crew day sheet): the signed-in person's own chip in a "who
   you're with" row -- surface fill plus a hairline, same treatment the
   mock's own .chip.you draws, distinguishing "you" from a name at a
   glance without a second colour. */
.chip.you{background:var(--surface);border-color:var(--hair);}
/* Q102: the who-you're-with row and its solo-day explainer line, plus
   the job-group card sticky header (Q115) -- one card per job on the
   crew day sheet, its own identity pinned while its sections scroll by. */
.withrow{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:6px;}
.alonerow{font-size:13px;color:var(--grey);margin-top:6px;}
.groupcard{background:var(--surface);border-radius:var(--radius);box-shadow:var(--sh-1);margin-bottom:12px;}
/* Fixes run Phase 3a (decision 176, 10 August 2026): the day sheet's
   own header (title, times, crew chips, address, drawings) took too
   much of a phone screen pinned in place -- removed entirely, everything
   in .grouphead now scrolls with .groupsections beneath it. */
.grouphead{background:var(--surface);border-radius:var(--radius) var(--radius) 0 0;padding:14px 15px 4px;}
.groupsections{padding:0 15px 10px;}
/* Q143: "Your day," Schedule Today's own shortcut into the crew day
   sheet -- adapted from the mock's .yourday/.ydrow/.ydic/.ydb/.ydt/.ydm/
   .ydgo onto this app's own tokens (--fill/--green in place of the
   mock's own --green-soft/--green-ink, which don't exist here; --card's
   own --sh-1/--hair in place of --sh-sm/--hairline). */
.yourday{background:var(--surface);border-radius:var(--radius);box-shadow:var(--sh-1);margin-bottom:12px;overflow:hidden;}
.ydrow{display:flex;align-items:center;gap:12px;width:100%;min-height:48px;padding:12px 15px;
  text-align:left;border-top:1px solid var(--hair);background:none;}
.ydrow:first-of-type{border-top:0;}
.ydic{width:30px;height:30px;flex:0 0 30px;border-radius:50%;display:grid;place-items:center;background:var(--fill);color:var(--green);}
.ydic svg{width:16px;height:16px;display:block;}
.ydb{flex:1;min-width:0;}
.ydt{display:block;font-size:14px;font-weight:500;line-height:1.3;color:var(--ink);}
.ydm{display:block;font-size:12px;color:var(--grey);margin-top:2px;}
.ydgo{width:16px;height:16px;flex:0 0 16px;color:var(--faint);display:block;}
/* v1.4 block 3 amendment: the hat mark, display-only wherever a lead
   exists but no 48px target is on offer (chips, grid cells, roster rows,
   My Week). Same glyph as the interactive .hardhat, sized down to sit
   inline with text. Never a control on its own. */
.leadmark{display:inline-flex;color:var(--green);flex:0 0 auto;}
.leadmark svg{width:12px;height:12px;}
.rdotext{color:var(--green) !important;font-weight:600;}
.awaytext{color:var(--warn-ink) !important;font-weight:600;}

/* v1.6 block 6: the job sheet's own crew-by-day grid (.wkgrid/.wg-name/
   .wg-cell/.wg-clash, and the .wg-row.wg-head header-row combo) is
   retired -- date strip pattern per v1.4 block 5, see jobSheetBody.
   .wg-row and .wg-dayb stay: the new-job wizard's own day picker
   (newJobStep2Body) still uses both, unrelated to the removed grid. */
/* G defect 2: seven columns at 48px each plus gaps (354px) don't fit
   the ~324px a 360px viewport leaves after the sheet's own padding, so
   flex:1 1 0 with no floor measured 43.1x48 -- shrinking to fit rather
   than breaching the floor. A hard 48px floor and zero horizontal
   overflow can't both hold for seven fixed columns in that width at
   once; this takes the same internal-scroll pattern the date strip
   above already uses for the identical problem (.daystrip), rather
   than silently accepting either a sub-48px target or a page overflow. */
.wg-row{
  display:flex;gap:3px;align-items:center;margin-bottom:3px;
  overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;
}
.wg-row::-webkit-scrollbar{display:none;}
/* job day toggles: the new-job day picker (and, before v1.6 block 6,
   the crew grid's header row). Green on means the JOB is scheduled that
   day. */
.wg-dayb{
  flex:0 0 48px;min-height:48px;border-radius:9px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:0;
  background:var(--surface);border:1px dashed var(--hair);
  font-size:9px;font-weight:500;color:var(--grey);
  transition:background .15s var(--ease),color .15s var(--ease),transform .15s var(--ease);
}
.wg-dayb:active{transform:scale(.93);}
.wg-dayb.on{background:var(--green);border:1px solid var(--green);color:var(--on-solid);}
.wg-dayb.rdo:not(.on){background:var(--fill);}
.wg-dayb .dn2{font-size:12px;font-weight:600;letter-spacing:0;font-variant-numeric:tabular-nums;}
/* CB-14: advisory tone only, never warn — see the daypill .phmark
   comment above for the full rationale */
.wg-dayb .rdomark{font-size:var(--fs-eyebrow);font-weight:700;letter-spacing:.02em;color:var(--green);}
.wg-dayb.on .rdomark{color:var(--on-dark-muted);}
.njdays .wg-row{margin-bottom:0;}

/* new-job wizard: job type chips, the composed-name preview and its Edit
   name toggle, the Add details disclosure, default/per-day time pairs */
.typechiprow{display:flex;flex-wrap:wrap;gap:8px;margin-top:2px;}
.typechip{
  min-height:48px;padding:0 16px;border-radius:var(--radius-pill);border:1px solid var(--hair);
  background:var(--surface);font-size:var(--fs-sub);font-weight:500;color:var(--grey);
  transition:background .15s var(--ease),color .15s var(--ease),transform .15s var(--ease);
}
.typechip:active{transform:scale(.96);}
.typechip.on{background:var(--solid);border-color:var(--solid);color:var(--on-solid);}
.edittoggle{
  display:inline-flex;align-items:center;justify-content:center;min-width:48px;min-height:48px;margin-top:2px;margin-right:16px;
  font-size:12.5px;font-weight:600;color:var(--green);
  transition:opacity .15s var(--ease);
}
.edittoggle:active{opacity:.6;}
/* Q116 (5 August 2026, pre-demo run): the two "+" affordance toggles --
   day-add-task's "+ Task" and mw-personal-add-toggle's "+ Add" -- take the
   same soft-fill/green pair .avatar, .hardhat.on, .typebadge.tone-accent and
   .statbadge.tone-accent already use for exactly this job. Scoped by
   data-action rather than a new class, so no markup change; every other
   .edittoggle (Day summary, Hide read, View archive, etc.) is untouched. */
.edittoggle[data-action="day-add-task"],
.edittoggle[data-action="mw-personal-add-toggle"]{
  background:var(--fill);border-radius:var(--radius-pill);padding:0 14px;
}
/* v1.6 block 6: the job-day schedule toggle sitting under the leadership
   job sheet's crew date strip -- was the old grid's own header row,
   now one full-width row scoped to whichever day the strip has
   selected. */
.jobdaytoggle{
  display:block;width:100%;text-align:left;min-height:48px;padding:8px 0;
  font-size:var(--fs-sub);font-weight:500;color:var(--grey);
  border-bottom:1px solid var(--hair);
  transition:opacity .15s var(--ease);
}
.jobdaytoggle:active{opacity:.6;}
.jobdaytoggle.on{color:var(--green);font-weight:600;}
/* register B5: the searchable provider combobox */
.providerrow{font-size:var(--fs-body);color:var(--ink);transition:background .15s var(--ease);}
.providerrow:active{background:var(--fill);}
.disclose{
  display:flex;align-items:center;justify-content:space-between;width:100%;
  min-height:48px;margin-top:16px;padding-top:12px;border-top:1px solid var(--hair);
  font-size:var(--fs-sub);font-weight:500;color:var(--ink);
  transition:opacity .15s var(--ease);
}
.disclose:active{opacity:.6;}
.disclose .car{width:16px;height:16px;flex:0 0 16px;color:var(--faint);transform:rotate(90deg);transition:transform .15s var(--ease);}
.disclose.open .car{transform:rotate(-90deg);}
.njdetails{margin-top:2px;}
.timepair{display:flex;gap:10px;}
.timepair > div{flex:1;min-width:0;}
.timeinput{font-variant-numeric:tabular-nums;}
.editedmark{
  display:inline-block;font-size:9px;font-weight:600;
  color:var(--green);background:var(--fill);padding:2px 7px;border-radius:var(--radius-pill);vertical-align:1px;
}
/* open-flag indicator: board card and My Week only, functional amber
   (v1.6 block 10: --warn split off --error; a flag reads --warn) */
.flagmark{
  display:inline-block;font-size:9px;font-weight:600;
  color:var(--on-semantic);background:var(--warn);padding:2px 7px;border-radius:var(--radius-pill);vertical-align:1px;
}
.daytimelist{display:flex;flex-direction:column;gap:8px;}
.daytimerow{border:1px solid var(--hair);border-radius:var(--radius-md);}
.daytimebtn{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  width:100%;min-height:48px;padding:0 14px;
  transition:opacity .15s var(--ease);
}
.daytimebtn:active{opacity:.6;}
.dtd{font-size:13.5px;font-weight:500;color:var(--ink);}
.dtr{font-size:12.5px;color:var(--grey);}
.daytimeedit{padding:2px 14px 14px;}

/* updates and flags: a flat per-job log. Flags use the one functional
   amber (--warn), reserved for this and for a genuine time clash. */
.noteitem{padding:10px 0;border-bottom:1px solid var(--hair);}
.noteitem:last-child{border-bottom:none;}
.notehead{display:flex;align-items:baseline;justify-content:space-between;gap:8px;}
.notekind{display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-eyebrow);font-weight:600;color:var(--grey);}
.notekind svg{width:13px;height:13px;flex:0 0 13px;}
.noteitem.flag .notekind{color:var(--warn-ink);}
.notewhen{font-size:var(--fs-fine);color:var(--grey);white-space:nowrap;}
/* Stage catch-up run, 7 Aug 2026, Phase 4: the as-built tag. Same shape
   as .daychip above; neutral grey-on-fill, not the warn tone, per the
   mock's own .dsg variant -- this is informational, not a warning, and
   the pack's own rule (see .needs above) is that raising attention and
   spending the attention colour don't share a control. */
.astag{display:inline-block;margin-left:6px;padding:2px 7px;border-radius:var(--radius-pill);background:var(--fill);color:var(--grey);font-size:var(--fs-eyebrow);font-weight:500;}
.notetext{font-size:13.5px;line-height:1.4;margin-top:3px;color:var(--ink);}
.notemeta{font-size:var(--fs-fine);color:var(--grey);margin-top:4px;}
.noteresolve{margin-top:8px;min-height:48px;padding:0 14px;}
.notecompose{margin-top:12px;}
.notecompose textarea.fieldinput{margin-top:10px;}
.notecompose .btn{margin-top:10px;}
.btn.warnbtn{background:var(--warn);color:var(--on-semantic);border-color:var(--warn);}

/* fabrication lane: a different lane on the board, but restrained. A
   faint tint and a left-edge marker in the one brand green, plus a
   small tag and glyph. No second accent colour anywhere here. */
.card.fabrication-job{background:var(--fill);border-left:3px solid var(--green);padding-left:15px;}
.fabricationtag{
  display:inline-flex;align-items:center;gap:4px;margin-left:6px;vertical-align:1px;
  font-size:9px;font-weight:600;color:var(--green);
  background:var(--surface);border:1px solid var(--hair);padding:2px 7px 2px 6px;border-radius:var(--radius-pill);
}
.fabricationtag svg{width:10px;height:10px;flex:0 0 10px;}
.fabricationglyph{color:var(--green);display:inline-block;vertical-align:-1px;margin-right:1px;}
/* register L2: accommodation only exists when there is accommodation --
   a chip, not a permanent "No overnight stay" line */
.attrchip{
  display:inline-flex;align-items:center;gap:6px;margin-top:8px;min-height:48px;
  font-size:12.5px;font-weight:600;color:var(--ink);
  background:var(--surface);border:1px solid var(--hair);padding:0 14px;border-radius:var(--radius-pill);
  transition:background .15s var(--ease);
}
.attrchip:active{background:var(--fill);}

/* collapsible sections on the job sheet (Contacts, Crew this week): a
   quiet header with a chevron, smooth height/opacity, remembered while
   the sheet is open (see ui.sheet.*Open) */
/* Projects walkthrough fixes run, 11 Aug 2026, Phase 6 (decision 195):
   measured 2px between two closed accordion rows stacked directly
   (Times/Taking to site/Materials/Plant on the stage sheet) -- read as
   no spacing at all, not a tight one. 8px, one declaration, app-wide
   (13 of these on a stage sheet alone, per the comment below). */
.accordion{background:var(--surface);padding:6px;border-radius:10px;margin:8px 0;}
/* D1's accordion promotion: dropping this to plain sentence-case body
   text like every other rule in the sweep would flatten the primary
   navigation of the deepest surface in the app (a stage sheet renders 13
   of these). It takes the section-title step instead -- 15px, weight
   600, ink, sentence case -- with the chevron still carrying the open
   state. accordionHtml (render.js:3495) composes the counter into the
   same label string rather than a separate element, and that function
   sits outside this run's six allowed render.js regions, so "counter in
   --grey beside it" could not be split out from the ink title text here
   -- logged as needs-approval for the surface pass. */
.accbtn{
  display:flex;align-items:center;justify-content:space-between;width:100%;
  min-height:48px;padding:6px;
  font-size:15px;font-weight:600;color:var(--ink);
  transition:opacity .15s var(--ease);
}
.accbtn:active{opacity:.6;}
/* U1/Q69 (5 August 2026): the counter half of the accordion promotion --
   the " &middot; N of M" tail of the label, split out in accordionHtml,
   renders lighter than the ink/600 title beside it. */
.accbtn .acccount{color:var(--grey);font-weight:500;}
.accbtn .car{width:15px;height:15px;flex:0 0 15px;color:var(--faint);transform:rotate(90deg);transition:transform .18s var(--ease);}
.accbtn.open .car{transform:rotate(-90deg);}
.accbody{max-height:0;opacity:0;overflow:hidden;transition:max-height .3s var(--ease),opacity .22s var(--ease);}
.accbody.open{max-height:2400px;opacity:1;}
/* Q114 (5 August 2026, night run): one section-header shape for every
   section on the stage sheet, whether always-open or collapsible -- the
   previous draft mixed an uppercase grey .eyebrow for the always-open
   ones with this 15px ink .accbtn for the collapsible ones, two rhythms
   down one card. .sech/.secv layer onto .accbtn (accordionHtml's own
   opts.rightValue) for the collapsible case; .sechead is the same shape
   with no button/chevron for a section with nothing to collapse.
   Matches claude_fen_taska_mock_crew_day_sheet_5aug.html's own .sec/
   .sech/.secv contract. A hairline above each header (not a divider
   between blocks) so the sections read as one list down the card. */
/* Decision 163 (10 August 2026): a closed section header draws as a
   filled row with a value pill; open is unchanged, flat with its
   hairline. The row and the pill swap which token they take so the pair
   always contrasts with whatever background it sits on: page background
   is the default, and any white surface (a bottom sheet, or a card on
   the page) swaps it. Two declarations because the pair swaps by
   context -- carried as variable inheritance rather than competing
   ancestor selectors, so a sheet-scoped and a card-scoped rule can never
   fight over source order the way decision 155's own fix had to watch
   for. */
:root{--acc-row:var(--surface);--acc-pill:var(--page-light);}
.sheet,.card,.groupcard{--acc-row:var(--page-light);--acc-pill:var(--surface);}
.accbtn.rightval{background:var(--acc-row);border-radius:var(--radius-badge);}
.accbtn.rightval.open{background:none;border-radius:0;border-top:1px solid var(--hair);}
/* Decision 196 (11 August 2026): decision 163's pairing (.secv + .car
   flattening the seam into one continuous pill) reverses here. It
   assumed the value and the chevron stay close in tone and the value
   never wraps -- neither held on the project page: --acc-row and
   --acc-pill swap by context (above), so inside a card the pairing
   put a surface-toned chevron pill hard against a page-light row, and
   a wrapped value pushed the chevron pill 1px past the card's own
   right edge on every valued row. The value pill now stands alone;
   the chevron is a bare glyph in the row, no pill of its own. */
.accbtn.rightval .secv{background:var(--acc-pill);border-radius:var(--radius-pill);padding:6px 11px;margin-left:auto;}
.accbtn.rightval .car{box-sizing:content-box;background:none;border-radius:0;padding:0;margin-left:8px;}
.accbtn.rightval.open .secv,.accbtn.rightval.open .car{background:none;border-radius:0;padding:0;}
.sech{flex:1;min-width:0;text-align:left;}
.secv{font-size:var(--fs-sub);font-weight:500;color:var(--grey);font-variant-numeric:tabular-nums;flex:0 0 auto;margin-left:10px;}
.secv.attn{color:var(--warn-ink);}
/* Run review, 11 August 2026 (Chantelle), redesigned same day (block 10
   wins -- decision 181 amended): the label lost the width contest to
   the value pill. Measured at 360px across the nine seeded projects,
   "Schedule" needs 75px and got 52 to 66px on six of them, so the fold
   read "Schedu" with no way to read the rest. The label is a short
   fixed vocabulary (Schedule, Tasks, Materials, Updates and flags); the
   value is the variable one, so the value yields first and wraps, and
   the label holds its content width. The flex priority (label fixed,
   value flexible) is the actual fix and is unchanged from the first
   pass -- only the ellipsis is gone. Do not re-add overflow:hidden or
   text-overflow:ellipsis to either rule; a value that doesn't fit wraps
   to a second line instead of clipping. Layout only, no markup change. */
.accbtn.rightval .sech{flex:0 0 auto;max-width:100%;}
.accbtn.rightval .secv{min-width:0;flex:0 1 auto;}
/* Task detail run, 7 August 2026, Phase 1: accordionHtml's opts.headerActions
   slot (additive). Reuses .sechrow above for the flex row -- same fix for
   the same "button can't nest a button" problem Q103's own "+" already
   solved -- but Q103's own .addbtn stays visible at all times, and this
   mock needs the opposite: the action hides while the section is closed,
   because adding to something you cannot see is noise. Plain sibling
   selector off .accbtn.open, no JS. */
.acchdactions{display:none;flex:0 0 auto;}
.accbtn.open + .acchdactions{display:flex;align-items:center;}
.sechead{display:flex;align-items:center;width:100%;min-height:48px;padding:6px 0;font-size:15px;font-weight:600;color:var(--ink);border-top:1px solid var(--hair);}
/* Suite health run, 9 August 2026: .shead (personSheetBody's "This week"
   row) had no rule at all, so <b> and <span> ran together as plain inline
   flow. Follows .sechead/.sech/.secv's own label-plus-value contract
   directly above -- flex row, label takes the remaining space, value is
   de-emphasised -- minus min-height/border-top, since .shead always sits
   right after its own .divider, which already provides the separation
   .sechead's border-top exists to give a header with no divider above it. */
.shead{display:flex;align-items:center;padding:6px 0;}
.shead b{flex:1;min-width:0;text-align:left;font-size:15px;font-weight:600;color:var(--ink);}
.shead span{font-size:var(--fs-sub);font-weight:500;color:var(--grey);font-variant-numeric:tabular-nums;flex:0 0 auto;margin-left:10px;}

/* Projects tab: a project card is collapsed by default, one open at a
   time. Same max-height/opacity motion language as the accordion above,
   killed globally under prefers-reduced-motion. */
.projcard{padding:0;overflow:hidden;}
/* register L4: the card title opens the project, the rest of the card
   still toggles the inline expansion -- two sibling buttons, not one
   (a button can't nest another, same reason as the assignrow/hardhat
   split), wrapped in a plain non-interactive column. */
.projhead{display:flex;flex-direction:column;width:100%;text-align:left;padding:14px 15px;}
.projheadname{display:flex;align-items:center;width:100%;min-height:48px;text-align:left;background:none;border:none;padding:0;}
.projheadname:active{background:var(--press-bg);}
/* Q32 (measured defect, Q21 Phase 3 independent verification, 4 August
   2026): half the 48px tap floor. width:100% already clears the
   min-width side of this on any real card, so only min-height needed
   raising. */
.projheadtoggle{display:flex;align-items:flex-start;gap:10px;width:100%;min-height:48px;text-align:left;background:none;border:none;padding:0;}
.projheadtoggle:active{background:var(--press-bg);}
.projhead .car{width:18px;height:18px;flex:0 0 18px;margin-top:3px;color:var(--faint);transform:rotate(90deg);transition:transform .18s var(--ease);}
.projhead.open .car{transform:rotate(-90deg);}
.projbody{max-height:0;opacity:0;overflow:hidden;transition:max-height .35s var(--ease),opacity .25s var(--ease);}
.projbody.open{max-height:3000px;opacity:1;}
.projbody-inner{padding:0 15px 15px;}
.qaction{
  display:inline-flex;align-items:center;gap:7px;min-height:48px;padding:0 14px;
  border-radius:var(--radius-pill);background:var(--fill);border:1px solid transparent;
  font-size:12.5px;font-weight:500;color:var(--ink);text-decoration:none;white-space:nowrap;
}
.qaction svg{flex:0 0 15px;color:var(--green);}
.qaction:active{opacity:.6;transform:scale(.97);}
.projjobs{margin-top:14px;padding-left:14px;border-left:2px solid var(--hair);}
.projjobrow{
  display:flex;align-items:center;gap:10px;width:100%;text-align:left;
  min-height:48px;padding:10px 0;border-bottom:1px solid var(--hair);
}
.projjobrow:last-child{border-bottom:none;}
.projjobrow:active{opacity:.7;}
.projjobrow .qi{flex:0 0 20px;color:var(--grey);}

/* job sheet rollup: "where is this job up to" at a glance */
.rollup{display:flex;flex-wrap:wrap;gap:10px 20px;margin-top:14px;padding:12px 14px;background:var(--fill);border-radius:var(--radius-md);}
.rollup .rstat{display:flex;flex-direction:column;gap:1px;min-width:56px;}
.rollup .rstat .rv{font-size:15px;font-weight:600;color:var(--ink);}
.rollup .rstat .rv.warn{color:var(--warn-ink);}
.rollup .rstat .rl{font-size:9px;font-weight:500;color:var(--grey);}

/* today's list rollup: a per-day summary. Adding is board-day-view-only,
   but each row is a tick target so it works from the job sheet too. */
.daysummary{border:1px solid var(--hair);border-radius:var(--radius-md);padding:10px 14px;margin-bottom:8px;}
.daysummary:last-child{margin-bottom:0;}

/* reduced motion: drop non-essential animation, keep everything usable */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation:none !important;transition:none !important;}
  .daystrip{scroll-snap-type:none;}
}
/* v1.3.1 item 6: the fen.taska loader plays on cold start only. Static
   markup, not JS-triggered — visible for whatever real time the browser
   takes to parse and execute this file on a cheap Android, then replaced
   the instant render() runs. Never shown again after boot. */
.bootload{min-height:100vh;min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:24px;}

/* ================================================================
   SECTION: UTILITY LAYER
   v1.6 block 3. The 45 static declarations repeated 3+ times across
   the app, one utility class each, generated by
   scripts/count-inline-styles.js and applied by
   scripts/migrate-inline-styles.js -- see docs/v1_6_build_log.md.
   Combined margin/padding shorthands (.my-T-B, .p-V-H) keep their
   exact original value rather than decomposing into separate
   top/bottom classes, since this file never resets margin/padding to
   0 on every element (only html/body) and decomposing would rely on
   an assumption about each element own browser default that does
   not always hold.
   ================================================================ */
.flex1{flex:1;}
.mt-10{margin-top:10px;}
.mt-8{margin-top:8px;}
.flex{display:flex;}
.minw0{min-width:0;}
.fs-sheet-title{font-size:var(--fs-sheet-title);}
.mt-6{margin-top:6px;}
.gap-8{gap:8px;}
.mt-2{margin-top:2px;}
.text-ink{color:var(--ink);}
.my-0-8{margin:0 0 8px;}
.minh-16{min-height:16px;}
.mt-14{margin-top:14px;}
.tap-target{min-height:48px;}
.my-8-0{margin:8px 0 0;}
.mt-12{margin-top:12px;}
.fs-15{font-size:15px;}
.mt-4{margin-top:4px;}
.text-green{color:var(--green);}
.w-full{width:100%;}
.fw-500{font-weight:500;}
.my-8-4{margin:8px 0 4px;}
.items-center{align-items:center;}
.text-left{text-align:left;}
.mb-8{margin-bottom:8px;}
.mb-4{margin-bottom:4px;}
.fw-600{font-weight:600;}
.my-22-10{margin:22px 0 10px;}
.my-0-2{margin:0 0 2px;}
.py-2{padding:2px 0;}
.my-0-4{margin:0 0 4px;}
.my-6-0{margin:6px 0 0;}
.fs-h2{font-size:var(--fs-h2);}
.my-2-0{margin:2px 0 0;}
.fs-body{font-size:var(--fs-body);}
.my-4-0{margin:4px 0 0;}
.my-18-8{margin:18px 0 8px;}
/* v1.7 block 8: renamed from my-12-8, tightened again -- the Factory
   eyebrow's own single-use spacing, part of the named j8/tab-bar 8px
   clearance fix on Schedule Today at 360x800. */
.my-8-6{margin:8px 0 6px;}
.p-0{padding:0;}
.m-0{margin:0;}
.no-border-bottom{border-bottom:none;}
.py-2-0{padding:2px 0 0;}
.flex-0-auto{flex:0 0 auto;}
.p-2-16{padding:2px 16px;}
.my-10-0{margin:10px 0 0;}
.mt-18{margin-top:18px;}

/* ================================================================
   PERSON SHEET: ROSTER ONTO A STAGE (Fixes run, 7 August 2026, Phase 3,
   Q142). Ported from claude_fen_taska_mock_person_v1_7aug.html, retokenised
   onto this app's own variables (--radius-pill not the mock's --r-pill,
   --press-bg not a literal hex). .covdots/.covdot (Schedule's own rail,
   styles.css above) are reused as-is for both the week rail and each
   stage row's day marks, per the mock's own "the shape of someone's week
   reads the same wherever you meet it." .daypill/.dw/.dn (the date-strip
   picker, styles.css above) are reused for the day-toggle grid, with one
   new .pat modifier for an off-pattern day -- a genuinely new component
   only where the shape doesn't already exist: the stage row, the clash
   line, and the stage picker itself.
   ================================================================ */
.wkrail{display:flex;align-items:center;gap:10px;padding:2px 0 8px;}
.wkrail .covdots{margin-top:0;}
.wkrail .rlbl{font-size:var(--fs-fine);color:var(--faint);}

.strow{display:flex;align-items:center;gap:11px;width:100%;min-height:48px;padding:11px 0;
  border-top:1px solid var(--hair);text-align:left;background:none;border-left:0;border-right:0;border-bottom:0;}
.strow:active{background:var(--press-bg);}
.strow .stb{flex:1;min-width:0;}
.strow .stt{display:block;font-size:var(--fs-body);font-weight:500;line-height:1.3;}
.strow .stm{display:block;font-size:12px;color:var(--grey);margin-top:2px;}
.strow .covdots{flex:none;}
.strow .car{width:15px;height:15px;color:var(--faint);flex:none;}

.clashline{font-size:12px;line-height:1.45;color:var(--warn-ink);background:var(--fill);
  border-radius:var(--radius-md);padding:9px 11px;margin:8px 0 0;}

.addstage{min-height:48px;display:flex;align-items:center;gap:9px;width:100%;
  color:var(--green);font-size:var(--fs-sub);font-weight:500;border-top:1px dashed var(--hair);
  margin-top:4px;border-radius:8px;background:none;border-left:0;border-right:0;border-bottom:0;text-align:left;}
.addstage:active{background:var(--fill);}
.addstage .plus{width:20px;height:20px;border-radius:50%;background:var(--fill);
  display:grid;place-items:center;flex:none;color:var(--green);font-size:14px;font-weight:600;line-height:1;}
/* Project page run, 10 August 2026, Phase 5 (decision 170): where two
   add-rows sit together, one dashed hairline over the pair, the rows
   themselves lose their own. */
.addpair{display:flex;gap:0 18px;flex-wrap:wrap;border-top:1px dashed var(--hair);margin-top:4px;}
.addpair .addstage{border-top:0;margin-top:0;width:auto;flex:0 1 auto;}

.stagepicker{border-top:1px solid var(--hair);margin-top:8px;padding-top:4px;}
.pickrow{display:flex;align-items:center;gap:11px;width:100%;min-height:48px;padding:10px 0;
  border-top:1px solid var(--hair);text-align:left;background:none;border-left:0;border-right:0;border-bottom:0;}
.pickrow:first-of-type{border-top:0;}
.pickrow:active{background:var(--press-bg);}
.pickrow.on .pickmark{background:var(--green);border-color:var(--green);}
.pickrow.on .pickmark svg{opacity:1;}
.pickmark{width:26px;height:26px;border-radius:50%;border:1.5px solid var(--line);
  display:grid;place-items:center;flex:none;}
.pickmark svg{opacity:0;}

.daygrid{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;margin:10px 0 2px;}
.daygrid .daypill{scroll-snap-align:unset;}
.daypill.pat{opacity:.55;}
.daypill.pat .dn{font-weight:500;}
.patnote{font-size:var(--fs-fine);color:var(--grey);line-height:1.5;margin:8px 0 0;}
.patnote b{color:var(--ink);font-weight:600;}
.sheetacts{display:flex;gap:8px;margin-top:14px;}
