/* source: public/fonts/pretendard mirror */
/**
 * Minified by jsDelivr using clean-css v5.3.3.
 * Original file: /gh/orioncactus/pretendard@1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.css
 *
 * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
 */
@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.0.woff2?v=8713e83342c3") format('woff2-variations');unicode-range:U+f9ca-fa0b,U+ff03-ff05,U+ff07,U+ff0a-ff0b,U+ff0d-ff19,U+ff1b,U+ff1d,U+ff20-ff5b,U+ff5d,U+ffe0-ffe3,U+ffe5-ffe6}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.1.woff2?v=b1c51b359646") format('woff2-variations');unicode-range:U+d723-d728,U+d72a-d733,U+d735-d748,U+d74a-d74f,U+d752-d753,U+d755-d757,U+d75a-d75f,U+d762-d764,U+d766-d768,U+d76a-d76b,U+d76d-d76f,U+d771-d787,U+d789-d78b,U+d78d-d78f,U+d791-d797,U+d79a,U+d79c,U+d79e-d7a3,U+f900-f909,U+f90b-f92e}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.2.woff2?v=ddc9557de55b") format('woff2-variations');unicode-range:U+d679-d68b,U+d68e-d69e,U+d6a0,U+d6a2-d6a7,U+d6a9-d6c3,U+d6c6-d6c7,U+d6c9-d6cb,U+d6cd-d6d3,U+d6d5-d6d6,U+d6d8-d6e3,U+d6e5-d6e7,U+d6e9-d6fb,U+d6fd-d717,U+d719-d71f,U+d721-d722}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.3.woff2?v=3af919db7b74") format('woff2-variations');unicode-range:U+d5bc-d5c7,U+d5ca-d5cb,U+d5cd-d5cf,U+d5d1-d5d7,U+d5d9-d5da,U+d5dc,U+d5de-d5e3,U+d5e6-d5e7,U+d5e9-d5eb,U+d5ed-d5f6,U+d5f8,U+d5fa-d5ff,U+d602-d603,U+d605-d607,U+d609-d60f,U+d612-d613,U+d616-d61b,U+d61d-d637,U+d63a-d63b,U+d63d-d63f,U+d641-d647,U+d64a-d64c,U+d64e-d653,U+d656-d657,U+d659-d65b,U+d65d-d666,U+d668,U+d66a-d678}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.4.woff2?v=993fcd2747f4") format('woff2-variations');unicode-range:U+d507,U+d509-d50b,U+d50d-d513,U+d515-d53b,U+d53e-d53f,U+d541-d543,U+d545-d54c,U+d54e,U+d550,U+d552-d557,U+d55a-d55b,U+d55d-d55f,U+d561-d564,U+d566-d567,U+d56a,U+d56c,U+d56e-d573,U+d576-d577,U+d579-d583,U+d585-d586,U+d58a-d5a4,U+d5a6-d5bb}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.5.woff2?v=a4ad435d7abd") format('woff2-variations');unicode-range:U+d464-d477,U+d47a-d47b,U+d47d-d47f,U+d481-d487,U+d489-d48a,U+d48c,U+d48e-d4e7,U+d4e9-d503,U+d505-d506}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.6.woff2?v=48b5ad9306b0") format('woff2-variations');unicode-range:U+d3bf-d3c7,U+d3ca-d3cf,U+d3d1-d3eb,U+d3ee-d3ef,U+d3f1-d3f3,U+d3f5-d3fb,U+d3fd-d400,U+d402-d45b,U+d45d-d463}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.7.woff2?v=0edd124bf5f5") format('woff2-variations');unicode-range:U+d2ff,U+d302-d304,U+d306-d30b,U+d30f,U+d311-d313,U+d315-d31b,U+d31e,U+d322-d324,U+d326-d327,U+d32a-d32b,U+d32d-d32f,U+d331-d337,U+d339-d33c,U+d33e-d37b,U+d37e-d37f,U+d381-d383,U+d385-d38b,U+d38e-d390,U+d392-d397,U+d39a-d39b,U+d39d-d39f,U+d3a1-d3a7,U+d3a9-d3aa,U+d3ac,U+d3ae-d3b3,U+d3b5-d3b7,U+d3b9-d3bb,U+d3bd-d3be}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.8.woff2?v=0fcc3858ccf1") format('woff2-variations');unicode-range:U+d257-d27f,U+d281-d29b,U+d29d-d29f,U+d2a1-d2ab,U+d2ad-d2b7,U+d2ba-d2bb,U+d2bd-d2bf,U+d2c1-d2c7,U+d2c9-d2ef,U+d2f2-d2f3,U+d2f5-d2f7,U+d2f9-d2fe}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.9.woff2?v=523e91cb7665") format('woff2-variations');unicode-range:U+d1b4,U+d1b6-d1f3,U+d1f5-d22b,U+d22e-d22f,U+d231-d233,U+d235-d23b,U+d23d-d240,U+d242-d256}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.10.woff2?v=544f73152519") format('woff2-variations');unicode-range:U+d105-d12f,U+d132-d133,U+d135-d137,U+d139-d13f,U+d141-d142,U+d144,U+d146-d14b,U+d14e-d14f,U+d151-d153,U+d155-d15b,U+d15e-d187,U+d189-d19f,U+d1a2-d1a3,U+d1a5-d1a7,U+d1a9-d1af,U+d1b2-d1b3}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.11.woff2?v=52f3cb7bf5d9") format('woff2-variations');unicode-range:U+d04b-d04f,U+d051-d057,U+d059-d06b,U+d06d-d06f,U+d071-d073,U+d075-d07b,U+d07e-d0a3,U+d0a6-d0a7,U+d0a9-d0ab,U+d0ad-d0b3,U+d0b6,U+d0b8,U+d0ba-d0bf,U+d0c2-d0c3,U+d0c5-d0c7,U+d0c9-d0cf,U+d0d2,U+d0d6-d0db,U+d0de-d0df,U+d0e1-d0e3,U+d0e5-d0eb,U+d0ee-d0f0,U+d0f2-d104}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.12.woff2?v=ba87086a06c3") format('woff2-variations');unicode-range:U+cfa2-cfc3,U+cfc5-cfdf,U+cfe2-cfe3,U+cfe5-cfe7,U+cfe9-cff4,U+cff6-cffb,U+cffd-cfff,U+d001-d003,U+d005-d017,U+d019-d033,U+d036-d037,U+d039-d03b,U+d03d-d04a}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.13.woff2?v=f9473c59d650") format('woff2-variations');unicode-range:U+cef0-cef3,U+cef6,U+cef9-ceff,U+cf01-cf03,U+cf05-cf07,U+cf09-cf0f,U+cf11-cf12,U+cf14-cf1b,U+cf1d-cf1f,U+cf21-cf2f,U+cf31-cf53,U+cf56-cf57,U+cf59-cf5b,U+cf5d-cf63,U+cf66,U+cf68,U+cf6a-cf6f,U+cf71-cf84,U+cf86-cf8b,U+cf8d-cfa1}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.14.woff2?v=dbf5fc513294") format('woff2-variations');unicode-range:U+ce3c-ce57,U+ce5a-ce5b,U+ce5d-ce5f,U+ce61-ce67,U+ce6a,U+ce6c,U+ce6e-ce73,U+ce76-ce77,U+ce79-ce7b,U+ce7d-ce83,U+ce85-ce88,U+ce8a-ce8f,U+ce91-ce93,U+ce95-ce97,U+ce99-ce9f,U+cea2,U+cea4-ceab,U+cead-cee3,U+cee6-cee7,U+cee9-ceeb,U+ceed-ceef}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.15.woff2?v=d043fdd0fb1d") format('woff2-variations');unicode-range:U+cd92-cd93,U+cd96-cd97,U+cd99-cd9b,U+cd9d-cda3,U+cda6-cda8,U+cdaa-cdaf,U+cdb1-cdc3,U+cdc5-cdcb,U+cdcd-cde7,U+cde9-ce03,U+ce05-ce1f,U+ce22-ce34,U+ce36-ce3b}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.16.woff2?v=f9da3e1e2f6a") format('woff2-variations');unicode-range:U+ccef-cd07,U+cd0a-cd0b,U+cd0d-cd1a,U+cd1c,U+cd1e-cd2b,U+cd2d-cd5b,U+cd5d-cd77,U+cd79-cd91}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.17.woff2?v=62a20965ab70") format('woff2-variations');unicode-range:U+cc3f-cc43,U+cc46-cc47,U+cc49-cc4b,U+cc4d-cc53,U+cc55-cc58,U+cc5a-cc5f,U+cc61-cc97,U+cc9a-cc9b,U+cc9d-cc9f,U+cca1-cca7,U+ccaa,U+ccac,U+ccae-ccb3,U+ccb6-ccb7,U+ccb9-ccbb,U+ccbd-cccf,U+ccd1-cce3,U+cce5-ccee}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.18.woff2?v=253726dfde63") format('woff2-variations');unicode-range:U+cb91-cbd3,U+cbd5-cbe3,U+cbe5-cc0b,U+cc0e-cc0f,U+cc11-cc13,U+cc15-cc1b,U+cc1d-cc20,U+cc23-cc27,U+cc2a-cc2b,U+cc2d,U+cc2f,U+cc31-cc37,U+cc3a,U+cc3c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.19.woff2?v=0c005e3239d3") format('woff2-variations');unicode-range:U+caf4-cb47,U+cb4a-cb90}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.20.woff2?v=06a4d6ce1c3e") format('woff2-variations');unicode-range:U+ca4a-ca4b,U+ca4e-ca4f,U+ca51-ca53,U+ca55-ca5b,U+ca5d-ca60,U+ca62-ca83,U+ca85-cabb,U+cabe-cabf,U+cac1-cac3,U+cac5-cacb,U+cacd-cad0,U+cad2,U+cad4-cad8,U+cada-caf3}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.21.woff2?v=30d4f324dc4e") format('woff2-variations');unicode-range:U+c996-c997,U+c99a-c99c,U+c99e-c9bf,U+c9c2-c9c3,U+c9c5-c9c7,U+c9c9-c9cf,U+c9d2,U+c9d4,U+c9d7-c9d8,U+c9db,U+c9de-c9df,U+c9e1-c9e3,U+c9e5-c9e6,U+c9e8-c9eb,U+c9ee-c9f0,U+c9f2-c9f7,U+c9f9-ca0b,U+ca0d-ca28,U+ca2a-ca49}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.22.woff2?v=5712a4ee03e8") format('woff2-variations');unicode-range:U+c8e9-c8f4,U+c8f6-c8fb,U+c8fe-c8ff,U+c901-c903,U+c905-c90b,U+c90e-c910,U+c912-c917,U+c919-c92b,U+c92d-c94f,U+c951-c953,U+c955-c96b,U+c96d-c973,U+c975-c987,U+c98a-c98b,U+c98d-c98f,U+c991-c995}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.23.woff2?v=bf5e603a72bc") format('woff2-variations');unicode-range:U+c841-c84b,U+c84d-c86f,U+c872-c873,U+c875-c877,U+c879-c87f,U+c882-c884,U+c887-c88a,U+c88d-c8c3,U+c8c5-c8df,U+c8e1-c8e8}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.24.woff2?v=d0cecc926613") format('woff2-variations');unicode-range:U+c779-c77b,U+c77e-c782,U+c786,U+c78b,U+c78d,U+c78f,U+c792-c793,U+c795,U+c797,U+c799-c79f,U+c7a2,U+c7a7-c7ab,U+c7ae-c7bb,U+c7bd-c7c0,U+c7c2-c7c7,U+c7c9-c7dc,U+c7de-c7ff,U+c802-c803,U+c805-c807,U+c809,U+c80b-c80f,U+c812,U+c814,U+c817-c81b,U+c81e-c81f,U+c821-c823,U+c825-c82e,U+c830-c837,U+c839-c83b,U+c83d-c840}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.25.woff2?v=4b520857cb0e") format('woff2-variations');unicode-range:U+c6bb-c6bf,U+c6c2,U+c6c4,U+c6c6-c6cb,U+c6ce-c6cf,U+c6d1-c6d3,U+c6d5-c6db,U+c6dd-c6df,U+c6e1-c6e7,U+c6e9-c6eb,U+c6ed-c6ef,U+c6f1-c6f8,U+c6fa-c703,U+c705-c707,U+c709-c70b,U+c70d-c716,U+c718,U+c71a-c71f,U+c722-c723,U+c725-c727,U+c729-c734,U+c736-c73b,U+c73e-c73f,U+c741-c743,U+c745-c74b,U+c74e-c750,U+c752-c757,U+c759-c773,U+c776-c777}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.26.woff2?v=608a2c01bc4e") format('woff2-variations');unicode-range:U+c5f5-c5fb,U+c5fe,U+c602-c605,U+c607,U+c609-c60f,U+c611-c61a,U+c61c-c623,U+c626-c627,U+c629-c62b,U+c62d,U+c62f-c632,U+c636,U+c638,U+c63a-c63f,U+c642-c643,U+c645-c647,U+c649-c652,U+c656-c65b,U+c65d-c65f,U+c661-c663,U+c665-c677,U+c679-c67b,U+c67d-c693,U+c696-c697,U+c699-c69b,U+c69d-c6a3,U+c6a6,U+c6a8,U+c6aa-c6af,U+c6b2-c6b3,U+c6b5-c6b7,U+c6b9-c6ba}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.27.woff2?v=8dcc8a46af70") format('woff2-variations');unicode-range:U+c517-c527,U+c52a-c52b,U+c52d-c52f,U+c531-c538,U+c53a,U+c53c,U+c53e-c543,U+c546-c547,U+c54b,U+c54d-c552,U+c556,U+c55a-c55b,U+c55d,U+c55f,U+c562-c563,U+c565-c567,U+c569-c56f,U+c572,U+c574,U+c576-c57b,U+c57e-c57f,U+c581-c583,U+c585-c586,U+c588-c58b,U+c58e,U+c590,U+c592-c596,U+c599-c5b3,U+c5b6-c5b7,U+c5ba,U+c5be-c5c3,U+c5ca-c5cb,U+c5cd,U+c5cf,U+c5d2-c5d3,U+c5d5-c5d7,U+c5d9-c5df,U+c5e1-c5e2,U+c5e4,U+c5e6-c5eb,U+c5ef,U+c5f1-c5f3}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.28.woff2?v=484aaea385bf") format('woff2-variations');unicode-range:U+c475-c4ef,U+c4f2-c4f3,U+c4f5-c4f7,U+c4f9-c4ff,U+c502-c50b,U+c50d-c516}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.29.woff2?v=5481a19ad606") format('woff2-variations');unicode-range:U+c3d0-c3d7,U+c3da-c3db,U+c3dd-c3de,U+c3e1-c3ec,U+c3ee-c3f3,U+c3f5-c42b,U+c42d-c463,U+c466-c474}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.30.woff2?v=c1ed2a2f2927") format('woff2-variations');unicode-range:U+c32b-c367,U+c36a-c36b,U+c36d-c36f,U+c371-c377,U+c37a-c37b,U+c37e-c383,U+c385-c387,U+c389-c3cf}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.31.woff2?v=95bd711a06b3") format('woff2-variations');unicode-range:U+c26a-c26b,U+c26d-c26f,U+c271-c273,U+c275-c27b,U+c27e-c287,U+c289-c28f,U+c291-c297,U+c299-c29a,U+c29c-c2a3,U+c2a5-c2a7,U+c2a9-c2ab,U+c2ad-c2b3,U+c2b6,U+c2b8,U+c2ba-c2bb,U+c2bd-c2db,U+c2de-c2df,U+c2e1-c2e2,U+c2e5-c2ea,U+c2ee,U+c2f0,U+c2f2-c2f5,U+c2f7,U+c2fa-c2fb,U+c2fd-c2ff,U+c301-c307,U+c309-c30c,U+c30e-c312,U+c315-c323,U+c325-c328,U+c32a}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.32.woff2?v=a2fb59661363") format('woff2-variations');unicode-range:U+c1bc-c1c3,U+c1c5-c1df,U+c1e1-c1fb,U+c1fd-c203,U+c205-c20c,U+c20e,U+c210-c217,U+c21a-c21b,U+c21d-c21e,U+c221-c227,U+c229-c22a,U+c22c,U+c22e,U+c230,U+c233-c24f,U+c251-c257,U+c259-c269}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.33.woff2?v=ec28ff655691") format('woff2-variations');unicode-range:U+c101-c11b,U+c11f,U+c121-c123,U+c125-c12b,U+c12e,U+c132-c137,U+c13a-c13b,U+c13d-c13f,U+c141-c147,U+c14a,U+c14c-c153,U+c155-c157,U+c159-c15b,U+c15d-c166,U+c169-c16f,U+c171-c177,U+c179-c18b,U+c18e-c18f,U+c191-c193,U+c195-c19b,U+c19d-c19e,U+c1a0,U+c1a2-c1a4,U+c1a6-c1bb}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.34.woff2?v=bdaffbd5c9fe") format('woff2-variations');unicode-range:U+c049-c057,U+c059-c05b,U+c05d-c05f,U+c061-c067,U+c069-c08f,U+c091-c0ab,U+c0ae-c0af,U+c0b1-c0b3,U+c0b5,U+c0b7-c0bb,U+c0be,U+c0c2-c0c7,U+c0ca-c0cb,U+c0cd-c0cf,U+c0d1-c0d7,U+c0d9-c0da,U+c0dc,U+c0de-c0e3,U+c0e5-c0eb,U+c0ed-c0f3,U+c0f6,U+c0f8,U+c0fa-c0ff}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.35.woff2?v=2f3c1deae814") format('woff2-variations');unicode-range:U+bfa7-bfaf,U+bfb1-bfc4,U+bfc6-bfcb,U+bfce-bfcf,U+bfd1-bfd3,U+bfd5-bfdb,U+bfdd-c048}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.36.woff2?v=d4e7580fb6bd") format('woff2-variations');unicode-range:U+bf07,U+bf09-bf3f,U+bf41-bf4f,U+bf52-bf54,U+bf56-bfa6}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.37.woff2?v=e5e19247f5eb") format('woff2-variations');unicode-range:U+be56,U+be58,U+be5c-be5f,U+be62-be63,U+be65-be67,U+be69-be74,U+be76-be7b,U+be7e-be7f,U+be81-be8e,U+be90,U+be92-bea7,U+bea9-becf,U+bed2-bed3,U+bed5-bed6,U+bed9-bee3,U+bee6-bf06}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.38.woff2?v=17226de7caa3") format('woff2-variations');unicode-range:U+bdb0-bdd3,U+bdd5-bdef,U+bdf1-be0b,U+be0d-be0f,U+be11-be13,U+be15-be43,U+be46-be47,U+be49-be4b,U+be4d-be53}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.39.woff2?v=647e3532e8e5") format('woff2-variations');unicode-range:U+bd03,U+bd06,U+bd08,U+bd0a-bd0f,U+bd11-bd22,U+bd25-bd47,U+bd49-bd58,U+bd5a-bd7f,U+bd82-bd83,U+bd85-bd87,U+bd8a-bd8f,U+bd91-bd92,U+bd94,U+bd96-bd98,U+bd9a-bdaf}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.40.woff2?v=12fb5a30e92e") format('woff2-variations');unicode-range:U+bc4e-bc83,U+bc86-bc87,U+bc89-bc8b,U+bc8d-bc93,U+bc96,U+bc98,U+bc9b-bc9f,U+bca2-bca3,U+bca5-bca7,U+bca9-bcb2,U+bcb4-bcbb,U+bcbe-bcbf,U+bcc1-bcc3,U+bcc5-bccc,U+bcce-bcd0,U+bcd2-bcd4,U+bcd6-bcf3,U+bcf7,U+bcf9-bcfb,U+bcfd-bd02}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.41.woff2?v=41d390d3f320") format('woff2-variations');unicode-range:U+bb90-bba3,U+bba5-bbab,U+bbad-bbbf,U+bbc1-bbf7,U+bbfa-bbfb,U+bbfd-bbfe,U+bc01-bc07,U+bc09-bc0a,U+bc0e,U+bc10,U+bc12-bc13,U+bc17,U+bc19-bc1a,U+bc1e,U+bc20-bc23,U+bc26,U+bc28,U+bc2a-bc2c,U+bc2e-bc2f,U+bc32-bc33,U+bc35-bc37,U+bc39-bc3f,U+bc41-bc42,U+bc44,U+bc46-bc48,U+bc4a-bc4d}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.42.woff2?v=3e347fc722ea") format('woff2-variations');unicode-range:U+bae6-bafb,U+bafd-bb17,U+bb19-bb33,U+bb37,U+bb39-bb3a,U+bb3d-bb43,U+bb45-bb46,U+bb48,U+bb4a-bb4f,U+bb51-bb53,U+bb55-bb57,U+bb59-bb62,U+bb64-bb8f}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.43.woff2?v=97a8be68deee") format('woff2-variations');unicode-range:U+ba30-ba37,U+ba3a-ba3b,U+ba3d-ba3f,U+ba41-ba47,U+ba49-ba4a,U+ba4c,U+ba4e-ba53,U+ba56-ba57,U+ba59-ba5b,U+ba5d-ba63,U+ba65-ba66,U+ba68-ba6f,U+ba71-ba73,U+ba75-ba77,U+ba79-ba84,U+ba86,U+ba88-baa7,U+baaa,U+baad-baaf,U+bab1-bab7,U+baba,U+babc,U+babe-bae5}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.44.woff2?v=8bd3bdcc7481") format('woff2-variations');unicode-range:U+b96e-b973,U+b976-b977,U+b979-b97b,U+b97d-b983,U+b986,U+b988,U+b98a-b98d,U+b98f-b9ab,U+b9ae-b9af,U+b9b1-b9b3,U+b9b5-b9bb,U+b9be,U+b9c0,U+b9c2-b9c7,U+b9ca-b9cb,U+b9cd,U+b9d2-b9d7,U+b9da,U+b9dc,U+b9df-b9e0,U+b9e2,U+b9e6-b9e7,U+b9e9-b9f3,U+b9f6,U+b9f8,U+b9fb-ba2f}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.45.woff2?v=dff46d20074b") format('woff2-variations');unicode-range:U+b8bf-b8cb,U+b8cd-b8e0,U+b8e2-b8e7,U+b8ea-b8eb,U+b8ed-b8ef,U+b8f1-b8f7,U+b8fa,U+b8fc,U+b8fe-b903,U+b905-b917,U+b919-b91f,U+b921-b93b,U+b93d-b957,U+b95a-b95b,U+b95d-b95f,U+b961-b967,U+b969-b96c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.46.woff2?v=c443e627e1bc") format('woff2-variations');unicode-range:U+b80d-b80f,U+b811-b817,U+b81a,U+b81c-b823,U+b826-b827,U+b829-b82b,U+b82d-b833,U+b836,U+b83a-b83f,U+b841-b85b,U+b85e-b85f,U+b861-b863,U+b865-b86b,U+b86e,U+b870,U+b872-b8af,U+b8b1-b8be}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.47.woff2?v=f242e40d23d0") format('woff2-variations');unicode-range:U+b74d-b75f,U+b761-b763,U+b765-b774,U+b776-b77b,U+b77e-b77f,U+b781-b783,U+b785-b78b,U+b78e,U+b792-b796,U+b79a-b79b,U+b79d-b7a7,U+b7aa,U+b7ae-b7b3,U+b7b6-b7c8,U+b7ca-b7eb,U+b7ee-b7ef,U+b7f1-b7f3,U+b7f5-b7fb,U+b7fe,U+b802-b806,U+b80a-b80b}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.48.woff2?v=e3dde5ed049d") format('woff2-variations');unicode-range:U+b6a7-b6aa,U+b6ac-b6b0,U+b6b2-b6ef,U+b6f1-b727,U+b72a-b72b,U+b72d-b72e,U+b731-b737,U+b739-b73a,U+b73c-b743,U+b745-b74c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.49.woff2?v=5bbf61d013a4") format('woff2-variations');unicode-range:U+b605-b60f,U+b612-b617,U+b619-b624,U+b626-b69b,U+b69e-b6a3,U+b6a5-b6a6}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.50.woff2?v=f3bb8007d522") format('woff2-variations');unicode-range:U+b55f,U+b562-b583,U+b585-b59f,U+b5a2-b5a3,U+b5a5-b5a7,U+b5a9-b5b2,U+b5b5-b5ba,U+b5bd-b604}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.51.woff2?v=530c8e2d2a5e") format('woff2-variations');unicode-range:U+b4a5-b4b6,U+b4b8-b4bf,U+b4c1-b4c7,U+b4c9-b4db,U+b4de-b4df,U+b4e1-b4e2,U+b4e5-b4eb,U+b4ee,U+b4f0,U+b4f2-b513,U+b516-b517,U+b519-b51a,U+b51d-b523,U+b526,U+b528,U+b52b-b52f,U+b532-b533,U+b535-b537,U+b539-b53f,U+b541-b544,U+b546-b54b,U+b54d-b54f,U+b551-b55b,U+b55d-b55e}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.52.woff2?v=93f30e304a97") format('woff2-variations');unicode-range:U+b3f8-b3fb,U+b3fd-b40f,U+b411-b417,U+b419-b41b,U+b41d-b41f,U+b421-b427,U+b42a-b42b,U+b42d-b44f,U+b452-b453,U+b455-b457,U+b459-b45f,U+b462-b464,U+b466-b46b,U+b46d-b47f,U+b481-b4a3}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.53.woff2?v=d0fe78c3e77b") format('woff2-variations');unicode-range:U+b342-b353,U+b356-b357,U+b359-b35b,U+b35d-b35e,U+b360-b363,U+b366,U+b368,U+b36a-b36d,U+b36f,U+b372-b373,U+b375-b377,U+b379-b37f,U+b381-b382,U+b384,U+b386-b38b,U+b38d-b3c3,U+b3c6-b3c7,U+b3c9-b3ca,U+b3cd-b3d3,U+b3d6,U+b3d8,U+b3da-b3f7}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.54.woff2?v=37ed0b796e61") format('woff2-variations');unicode-range:U+b27c-b283,U+b285-b28f,U+b292-b293,U+b295-b297,U+b29a-b29f,U+b2a1-b2a4,U+b2a7-b2a9,U+b2ab,U+b2ad-b2c7,U+b2ca-b2cb,U+b2cd-b2cf,U+b2d1-b2d7,U+b2da,U+b2dc,U+b2de-b2e3,U+b2e7,U+b2e9-b2ea,U+b2ef-b2f3,U+b2f6,U+b2f8,U+b2fa-b2fb,U+b2fd-b2fe,U+b302-b303,U+b305-b307,U+b309-b30f,U+b312,U+b316-b31b,U+b31d-b341}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.55.woff2?v=4b170f37c7be") format('woff2-variations');unicode-range:U+b1d6-b1e7,U+b1e9-b1fc,U+b1fe-b203,U+b206-b207,U+b209-b20b,U+b20d-b213,U+b216-b21f,U+b221-b257,U+b259-b273,U+b275-b27b}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.56.woff2?v=0f3624847670") format('woff2-variations');unicode-range:U+b120-b122,U+b126-b127,U+b129-b12b,U+b12d-b133,U+b136,U+b138,U+b13a-b13f,U+b142-b143,U+b145-b14f,U+b151-b153,U+b156-b157,U+b159-b177,U+b17a-b17b,U+b17d-b17f,U+b181-b187,U+b189-b18c,U+b18e-b191,U+b195-b1a7,U+b1a9-b1cb,U+b1cd-b1d5}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.57.woff2?v=7c6aa4751ceb") format('woff2-variations');unicode-range:U+b05f-b07b,U+b07e-b07f,U+b081-b083,U+b085-b08b,U+b08d-b097,U+b09b,U+b09d-b09f,U+b0a2-b0a7,U+b0aa,U+b0b0,U+b0b2,U+b0b6-b0b7,U+b0b9-b0bb,U+b0bd-b0c3,U+b0c6-b0c7,U+b0ca-b0cf,U+b0d1-b0df,U+b0e1-b0e4,U+b0e6-b107,U+b10a-b10b,U+b10d-b10f,U+b111-b112,U+b114-b117,U+b119-b11a,U+b11c-b11f}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.58.woff2?v=cff4a57ea5e9") format('woff2-variations');unicode-range:U+afac-afb7,U+afba-afbb,U+afbd-afbf,U+afc1-afc6,U+afca-afcc,U+afce-afd3,U+afd5-afe7,U+afe9-afef,U+aff1-b00b,U+b00d-b00f,U+b011-b013,U+b015-b01b,U+b01d-b027,U+b029-b043,U+b045-b047,U+b049,U+b04b,U+b04d-b052,U+b055-b056,U+b058-b05c,U+b05e}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.59.woff2?v=4ae337e8895a") format('woff2-variations');unicode-range:U+af03-af07,U+af09-af2b,U+af2e-af33,U+af35-af3b,U+af3e-af40,U+af44-af47,U+af4a-af5c,U+af5e-af63,U+af65-af7f,U+af81-afab}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.60.woff2?v=4f6724848817") format('woff2-variations');unicode-range:U+ae56-ae5b,U+ae5e-ae60,U+ae62-ae64,U+ae66-ae67,U+ae69-ae6b,U+ae6d-ae83,U+ae85-aebb,U+aebf,U+aec1-aec3,U+aec5-aecb,U+aece,U+aed0,U+aed2-aed7,U+aed9-aef3,U+aef5-af02}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.61.woff2?v=0f36628cfb62") format('woff2-variations');unicode-range:U+ad9c-ada3,U+ada5-adbf,U+adc1-adc3,U+adc5-adc7,U+adc9-add2,U+add4-addb,U+addd-addf,U+ade1-ade3,U+ade5-adf7,U+adfa-adfb,U+adfd-adff,U+ae02-ae07,U+ae0a,U+ae0c,U+ae0e-ae13,U+ae15-ae2f,U+ae31-ae33,U+ae35-ae37,U+ae39-ae3f,U+ae42,U+ae44,U+ae46-ae49,U+ae4b,U+ae4f,U+ae51-ae53,U+ae55}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.62.woff2?v=1a2f8d760e6b") format('woff2-variations');unicode-range:U+ace2-ace3,U+ace5-ace6,U+ace9-acef,U+acf2,U+acf4,U+acf7-acfb,U+acfe-acff,U+ad01-ad03,U+ad05-ad0b,U+ad0d-ad10,U+ad12-ad1b,U+ad1d-ad33,U+ad35-ad48,U+ad4a-ad4f,U+ad51-ad6b,U+ad6e-ad6f,U+ad71-ad72,U+ad77-ad7c,U+ad7e,U+ad80,U+ad82-ad87,U+ad89-ad8b,U+ad8d-ad8f,U+ad91-ad9b}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.63.woff2?v=cced20f44344") format('woff2-variations');unicode-range:U+ac25-ac2c,U+ac2e,U+ac30,U+ac32-ac37,U+ac39-ac3f,U+ac41-ac4c,U+ac4e-ac6f,U+ac72-ac73,U+ac75-ac76,U+ac79-ac7f,U+ac82,U+ac84-ac88,U+ac8a-ac8b,U+ac8d-ac8f,U+ac91-ac93,U+ac95-ac9b,U+ac9d-ac9e,U+aca1-aca7,U+acab,U+acad-acaf,U+acb1-acb7,U+acba-acbb,U+acbe-acc0,U+acc2-acc3,U+acc5-acdf}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.64.woff2?v=4d73796ddeaf") format('woff2-variations');unicode-range:U+99df,U+99ed,U+99f1,U+99ff,U+9a01,U+9a08,U+9a0e-9a0f,U+9a19,U+9a2b,U+9a30,U+9a36-9a37,U+9a40,U+9a43,U+9a45,U+9a4d,U+9a55,U+9a57,U+9a5a-9a5b,U+9a5f,U+9a62,U+9a65,U+9a69-9a6a,U+9aa8,U+9ab8,U+9ad3,U+9ae5,U+9aee,U+9b1a,U+9b27,U+9b2a,U+9b31,U+9b3c,U+9b41-9b45,U+9b4f,U+9b54,U+9b5a,U+9b6f,U+9b8e,U+9b91,U+9b9f,U+9bab,U+9bae,U+9bc9,U+9bd6,U+9be4,U+9be8,U+9c0d,U+9c10,U+9c12,U+9c15,U+9c25,U+9c32,U+9c3b,U+9c47,U+9c49,U+9c57,U+9ce5,U+9ce7,U+9ce9,U+9cf3-9cf4,U+9cf6,U+9d09,U+9d1b,U+9d26,U+9d28,U+9d3b,U+9d51,U+9d5d,U+9d60-9d61,U+9d6c,U+9d72,U+9da9,U+9daf,U+9db4,U+9dc4,U+9dd7,U+9df2,U+9df8-9dfa,U+9e1a,U+9e1e,U+9e75,U+9e79,U+9e7d,U+9e7f,U+9e92-9e93,U+9e97,U+9e9d,U+9e9f,U+9ea5,U+9eb4-9eb5,U+9ebb,U+9ebe,U+9ec3,U+9ecd-9ece,U+9ed4,U+9ed8,U+9edb-9edc,U+9ede,U+9ee8,U+9ef4,U+9f07-9f08,U+9f0e,U+9f13,U+9f20,U+9f3b,U+9f4a-9f4b,U+9f4e,U+9f52,U+9f5f,U+9f61,U+9f67,U+9f6a,U+9f6c,U+9f77,U+9f8d,U+9f90,U+9f95,U+9f9c,U+ac02-ac03,U+ac05-ac06,U+ac09-ac0f,U+ac17-ac18,U+ac1b,U+ac1e-ac1f,U+ac21-ac23}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.65.woff2?v=3bea94ae7ab0") format('woff2-variations');unicode-range:U+338c-339c,U+339f-33a0,U+33a2-33cb,U+33cf-33d0,U+33d3,U+33d6,U+33d8,U+33db-33dd,U+4e01,U+4e03,U+4e07-4e08,U+4e11,U+4e14-4e15,U+4e18-4e19,U+4e1e,U+4e32,U+4e38-4e39,U+4e42-4e43,U+4e45,U+4e4d-4e4f,U+4e56,U+4e58-4e59,U+4e5d-4e5e,U+4e6b,U+4e6d,U+4e73,U+4e76-4e77,U+4e7e,U+4e82,U+4e86,U+4e88,U+4e8e,U+4e90-4e92,U+4e94-4e95,U+4e98,U+4e9b,U+4e9e,U+4ea1-4ea2,U+4ea4-4ea6,U+4ea8,U+4eab,U+4ead-4eae,U+4eb6,U+4ec0-4ec1,U+4ec4,U+4ec7,U+4ecb,U+4ecd,U+4ed4-4ed5,U+4ed7-4ed9,U+4edd,U+4edf,U+4ee4,U+4ef0,U+4ef2,U+4ef6-4ef7,U+4efb,U+4f01,U+4f09,U+4f0b,U+4f0d-4f11,U+4f2f,U+4f34,U+4f36,U+4f38,U+4f3a,U+4f3c-4f3d}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.66.woff2?v=73d60e9ad890") format('woff2-variations');unicode-range:U+3136,U+3138,U+313a-3140,U+3143-3144,U+3150,U+3152,U+3154-3156,U+3158-315b,U+315d-315f,U+3162,U+3164-318c,U+318e,U+3200-321b,U+3231,U+3239,U+3251-325a,U+3260-327b,U+327e-327f,U+328a-3290,U+3294,U+329e,U+32a5,U+3380-3384,U+3388-338b}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.67.woff2?v=24e38abaccea") format('woff2-variations');unicode-range:U+2f7d,U+2f7f-2f8b,U+2f8e-2f90,U+2f92-2f97,U+2f99-2fa0,U+2fa2-2fa3,U+2fa5-2fa9,U+2fac-2fb1,U+2fb3-2fbc,U+2fc1-2fca,U+2fcd-2fd4,U+3003,U+3012-3019,U+301c,U+301e-3020,U+3036,U+3041,U+3043,U+3045,U+3047,U+3049,U+304e,U+3050,U+3052,U+3056,U+305a,U+305c,U+305e,U+3062,U+3065,U+306c,U+3070-307d,U+3080,U+3085,U+3087,U+308e,U+3090-3091,U+30a1,U+30a5,U+30a9,U+30ae,U+30b1-30b2,U+30b4,U+30b6,U+30bc-30be,U+30c2,U+30c5,U+30cc,U+30d2,U+30d4,U+30d8-30dd,U+30e4,U+30e6,U+30e8,U+30ee,U+30f0-30f2,U+30f4-30f6,U+3133,U+3135}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.68.woff2?v=a0f33cbfd1a4") format('woff2-variations');unicode-range:U+2541-254b,U+25a4-25a9,U+25b1,U+25b5,U+25b9,U+25bf,U+25c1,U+25c3,U+25c9-25ca,U+25cc,U+25ce,U+25d0-25d1,U+25e6,U+25ef,U+260f,U+261d,U+261f,U+262f,U+2660,U+2664,U+2667-2669,U+266d,U+266f,U+2716,U+271a,U+273d,U+2756,U+2776-277f,U+278a-2793,U+2963,U+2965,U+2ac5-2ac6,U+2acb-2acc,U+2f00,U+2f04,U+2f06,U+2f08,U+2f0a-2f0b,U+2f11-2f12,U+2f14,U+2f17-2f18,U+2f1c-2f1d,U+2f1f-2f20,U+2f23-2f26,U+2f28-2f29,U+2f2b,U+2f2d,U+2f2f-2f32,U+2f38,U+2f3c-2f40,U+2f42-2f4c,U+2f4f-2f52,U+2f54-2f58,U+2f5a-2f66,U+2f69-2f70,U+2f72-2f76,U+2f78,U+2f7a-2f7c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.69.woff2?v=c9aa76582f8f") format('woff2-variations');unicode-range:U+2479-2487,U+249c-24d1,U+24d3-24d7,U+24d9-24e9,U+24eb-24f4,U+2500-2501,U+2503,U+250c-2513,U+2515-2516,U+2518-2540}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.70.woff2?v=8bccc361d2d7") format('woff2-variations');unicode-range:U+215b-215e,U+2162-2169,U+2170-2179,U+2195-2199,U+21b0-21b4,U+21bc,U+21c0,U+21c4-21c5,U+21cd,U+21cf-21d4,U+21e0-21e3,U+21e6-21e9,U+2200,U+2202-2203,U+2206-2209,U+220b-220c,U+220f,U+2211,U+2213,U+221a,U+221d-2220,U+2222,U+2225-2227,U+2229-222c,U+222e,U+2234-2237,U+223d,U+2243,U+2245,U+2248,U+2250-2253,U+225a,U+2260-2262,U+2264-2267,U+226a-226b,U+226e-2273,U+2276-2277,U+2279-227b,U+2280-2287,U+228a-228b,U+2295-2297,U+22a3-22a5,U+22bb-22bc,U+22ce-22cf,U+22da-22db,U+22ee-22ef,U+2306,U+2312,U+2314,U+2467-2478}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.71.woff2?v=78ca0ca3a02f") format('woff2-variations');unicode-range:U+81-82,U+84,U+a2-a5,U+a7-a8,U+aa,U+ac,U+b1-b3,U+b6,U+b8-ba,U+bc-be,U+c0,U+c2,U+c6-cb,U+ce-d0,U+d4,U+d8-d9,U+db-dc,U+de-df,U+e6,U+eb,U+ee-f0,U+f4,U+f7-f9,U+fb,U+fe-ff,U+111,U+126-127,U+132-133,U+138,U+13f-142,U+149-14b,U+152-153,U+166-167,U+2bc,U+2c7,U+2d0,U+2d8-2d9,U+2db-2dd,U+391-394,U+396-3a1,U+3a3-3a9,U+3b2-3b6,U+3b8,U+3bc,U+3be-3c1,U+3c3-3c9,U+2010,U+2015-2016,U+2018-2019,U+201b,U+201f-2021,U+2025,U+2030,U+2033-2036,U+203c,U+203e,U+2042,U+2074,U+207a-207f,U+2081-2084,U+2109,U+2113,U+2116,U+2121,U+2126,U+212b,U+2153-2154}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.72.woff2?v=a2df48a0029f") format('woff2-variations');unicode-range:U+e8,U+2da,U+2160,U+2194,U+3054,U+3058,U+306d,U+3086,U+308d,U+30ac,U+30bb,U+30c4,U+30cd-30ce,U+30e2,U+3132,U+3146,U+3149,U+339d,U+4e3b,U+4f0a,U+4fdd,U+4fe1,U+5409,U+540c,U+5834,U+592a-592b,U+5b9a,U+5dde,U+5e0c,U+5e73,U+5f0f,U+60f3,U+653f,U+661f,U+662f,U+667a,U+683c,U+6b4c,U+6c11,U+767c,U+76ee,U+76f4,U+77f3,U+79d1,U+7a7a,U+7b2c,U+7d22,U+8207,U+8a00,U+8a71,U+9280,U+9580,U+958b,U+96c6,U+9762,U+98df,U+9ed1,U+ac2d,U+adc8,U+add3,U+af48,U+b014,U+b134-b135,U+b158,U+b2aa,U+b35f,U+b6a4,U+b9cf,U+bb63,U+bd23,U+be91,U+c29b,U+c3f4,U+c42c,U+c55c,U+c573,U+c58f,U+c78c,U+c7dd,U+c8f5,U+cad1,U+cc48,U+cf10,U+cf20,U+d03c,U+d07d,U+d2a0,U+d30e,U+d38d,U+d3a8,U+d3c8,U+d5e5,U+d5f9,U+d6e4,U+f90a,U+ff02,U+ff1c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.73.woff2?v=fe4874885e64") format('woff2-variations');unicode-range:U+3b1,U+2466,U+25a1,U+25a3,U+261c,U+3008-3009,U+305b,U+305d,U+3069,U+30a7,U+30ba,U+30cf,U+30ef,U+3151,U+3157,U+4e4b,U+4e5f,U+4e8c,U+4eca,U+4ed6,U+4f5b,U+50cf,U+5149,U+5165,U+5171,U+5229,U+529b,U+5316,U+539f,U+53f2,U+571f,U+5728,U+58eb,U+591c,U+5b78,U+5c11,U+5c55,U+5ddd,U+5e02,U+5fb7,U+60c5,U+610f,U+611f,U+6625,U+66f8,U+6797,U+679c,U+682a,U+6d2a,U+706b,U+7406,U+767b,U+76f8,U+77e5,U+7acb,U+898b,U+8a69,U+8def,U+8fd1,U+901a,U+90e8,U+91cd,U+975e,U+ae14,U+ae6c,U+aec0,U+afc7,U+afc9,U+b01c,U+b028,U+b308,U+b311,U+b314,U+b31c,U+b524,U+b560,U+b764,U+b920,U+b9e3,U+bd48,U+be7d,U+c0db,U+c231,U+c270,U+c2e3,U+c37d,U+c3ed,U+c530,U+c6a5,U+c6dc,U+c7a4,U+c954,U+c974,U+d000,U+d565,U+d667,U+d6c5,U+d79d,U+ff1e}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.74.woff2?v=b935b4839e30") format('woff2-variations');unicode-range:U+131,U+2032,U+2465,U+2642,U+3048,U+3051,U+3083-3084,U+308f,U+30c0,U+30d1,U+30d3,U+30d6,U+30df,U+30e7,U+3153,U+4e16,U+4e8b,U+4ee5,U+5206,U+52a0,U+52d5,U+53e4,U+53ef,U+54c1,U+57ce,U+597d,U+5b8c,U+5ea6,U+5f8c,U+5f97,U+6210,U+6240,U+624b,U+6728,U+6bd4,U+7236,U+7269,U+7279,U+738b,U+7528,U+7530,U+767e,U+798f,U+8005,U+8a18,U+90fd,U+91cc,U+9577,U+9593,U+98a8,U+ac20,U+acf6,U+ad90,U+af5d,U+af80,U+afcd,U+aff0,U+b0a1,U+b0b5,U+b1fd,U+b2fc,U+b380,U+b51b,U+b584,U+b5b3,U+b8fd,U+b93c,U+b9f4,U+bb44,U+bc08,U+bc27,U+bc49,U+be55,U+be64,U+bfb0,U+bfc5,U+c178,U+c21f,U+c314,U+c4f1,U+c58d,U+c664,U+c698,U+c6a7,U+c6c1,U+c9ed,U+cac0,U+cacc,U+cad9,U+ccb5,U+cdcc,U+d0e4,U+d143,U+d320,U+d330,U+d54d,U+ff06,U+ff1f,U+ff5e}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.75.woff2?v=07f0ddae65c8") format('woff2-variations');unicode-range:U+b4,U+20a9,U+20ac,U+2190,U+24d8,U+2502,U+2514,U+2592,U+25c7-25c8,U+2663,U+3060,U+3064,U+3081,U+3088,U+30a3,U+30a6,U+30aa,U+30b5,U+30c7,U+30ca-30cb,U+30d0,U+30e3,U+30e5,U+339e,U+4e09,U+4eac,U+4f5c,U+5167-5168,U+516c,U+51fa,U+5408,U+540d,U+591a,U+5b57,U+6211,U+65b9,U+660e,U+6642,U+6700,U+6b63,U+6e2f,U+7063,U+7532,U+793e,U+81ea,U+8272,U+82b1,U+897f,U+8eca,U+91ce,U+ac38,U+ad76,U+ae84,U+aecc,U+b07d,U+b0b1,U+b215,U+b2a0,U+b310,U+b3d7,U+b52a,U+b618,U+b775,U+b797,U+bcd5,U+bd59,U+be80,U+bea8,U+bed1,U+bee4-bee5,U+c060,U+c2ef,U+c329,U+c3dc,U+c597,U+c5bd,U+c5e5,U+c69c,U+c9d6,U+ca29,U+ca5c,U+ca84,U+cc39,U+cc3b,U+ce89,U+cee5,U+cf65,U+cf85,U+d058,U+d145,U+d22d,U+d325,U+d37d,U+d3ad,U+d769,U+ff0c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.76.woff2?v=20ccaae02a27") format('woff2-variations');unicode-range:U+2161,U+2228,U+2299,U+2464,U+2517,U+2640,U+3042,U+304a,U+3053,U+3061,U+307f,U+3082,U+308c,U+3092,U+30a8,U+30ab,U+30ad,U+30b0,U+30b3,U+30b7,U+30c1,U+30c6,U+30c9,U+30d5,U+30d7,U+30de,U+30e0-30e1,U+30ec-30ed,U+4e0b,U+4e0d,U+4ee3,U+53f0,U+548c,U+5b89,U+5bb6,U+5c0f,U+611b,U+6771,U+6aa2,U+6bcd,U+6c34,U+6cd5,U+6d77,U+767d,U+795e,U+8ecd,U+9999,U+9ad8,U+ac07,U+ac1a,U+ac40,U+ad0c,U+ad88,U+ada4,U+ae01,U+ae65,U+aebd,U+aec4,U+afe8,U+b139,U+b205,U+b383,U+b38c,U+b42c,U+b461,U+b55c,U+b78f,U+b8fb,U+b9f7,U+bafc,U+bc99,U+bed8,U+bfcd,U+c0bf,U+c0f9,U+c167,U+c204,U+c20f,U+c22f,U+c258,U+c298,U+c2bc,U+c388,U+c501,U+c50c,U+c5b9,U+c5ce,U+c641,U+c648,U+c73d,U+ca50,U+ca61,U+cc4c,U+ceac,U+d0d4,U+d5f7,U+d6d7,U+ff1a}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.77.woff2?v=9ab92ab7b4e3") format('woff2-variations');unicode-range:U+2103,U+2463,U+25c6,U+25cb,U+266c,U+3001,U+300a,U+3046,U+304c-304d,U+304f,U+3055,U+3059,U+3063,U+3066-3068,U+306f,U+3089,U+30b8,U+30bf,U+314f,U+4e0a,U+570b,U+5730,U+5916,U+5929,U+5c71,U+5e74,U+5fc3,U+601d,U+6027,U+63d0,U+6709,U+6734,U+751f,U+7684,U+82f1,U+9053,U+91d1,U+97f3,U+ac2f,U+ac4d,U+adc4,U+ade4,U+ae41,U+ae4d-ae4e,U+aed1,U+afb9,U+b0e0,U+b299,U+b365,U+b46c,U+b480,U+b4c8,U+b7b4,U+b819,U+b918,U+baab,U+bab9,U+be8f,U+bed7,U+c0ec,U+c19f,U+c1a5,U+c3d9,U+c464,U+c53d,U+c553,U+c570,U+c5cc,U+c633,U+c6a4,U+c7a3,U+c7a6,U+c886,U+c9d9-c9da,U+c9ec,U+ca0c,U+cc21,U+cd1b,U+cd78,U+cdc4,U+cef8,U+cfe4,U+d0a5,U+d0b5,U+d0ec,U+d15d,U+d188,U+d23c,U+d2ac,U+d729,U+d79b,U+ff01,U+ff08-ff09,U+ff5c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.78.woff2?v=67f065415552") format('woff2-variations');unicode-range:U+2039-203a,U+223c,U+25b3,U+25b7,U+25bd,U+25cf,U+266a,U+3002,U+300b,U+304b,U+3057,U+305f,U+306a-306b,U+307e,U+308a-308b,U+3093,U+30a2,U+30af,U+30b9,U+30c3,U+30c8,U+30e9-30eb,U+33a1,U+4e00,U+524d,U+5357,U+5b50,U+7121,U+884c,U+9751,U+ac94,U+aebe,U+aecd,U+af08,U+af41,U+af49,U+b010,U+b053,U+b109,U+b11b,U+b128,U+b154,U+b291,U+b2e6,U+b301,U+b385,U+b525,U+b5b4,U+b729,U+b72f,U+b738,U+b7ff,U+b837,U+b975,U+ba67,U+bb47,U+bc1f,U+bd90,U+bfd4,U+c27c,U+c324,U+c379,U+c3e0,U+c465,U+c53b,U+c58c,U+c610,U+c653,U+c6cd,U+c813,U+c82f,U+c999,U+c9e0,U+cac4,U+cad3,U+cbd4,U+cc10,U+cc22,U+ccb8,U+ccbc,U+cda5,U+ce84,U+cea3,U+cf67,U+cfe1,U+d241,U+d30d,U+d31c,U+d391,U+d401,U+d479,U+d5c9,U+d5db,U+d649,U+d6d4}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.79.woff2?v=0bbdf492d859") format('woff2-variations');unicode-range:U+b0,U+e9,U+2193,U+2462,U+260e,U+261e,U+300e-300f,U+3044,U+30a4,U+30fb-30fc,U+314d,U+5973,U+6545,U+6708,U+7537,U+ac89,U+ac9c,U+acc1,U+ad04,U+ad75,U+ad7d,U+ae45,U+ae61,U+af42,U+b0ab,U+b0af,U+b0b3,U+b12c,U+b194,U+b1a8,U+b220,U+b258,U+b284,U+b2ff,U+b315,U+b371,U+b3d4-b3d5,U+b460,U+b527,U+b534,U+b810,U+b818,U+b98e,U+ba55,U+bbac,U+bc0b,U+bc40,U+bca1,U+bccd,U+bd93,U+be54,U+be5a,U+bf08,U+bf50,U+bf55,U+bfdc,U+c0c0,U+c0d0,U+c0f4,U+c100,U+c11e,U+c170,U+c20d,U+c274,U+c290,U+c308,U+c369,U+c539,U+c587,U+c5ff,U+c6ec,U+c70c,U+c7ad,U+c7c8,U+c83c,U+c881,U+cb48,U+cc60,U+ce69,U+ce6b,U+ce75,U+cf04,U+cf08,U+cf55,U+cf70,U+cffc,U+d0b7,U+d1a8,U+d2c8,U+d384,U+d47c,U+d48b,U+d5dd,U+d5e8,U+d720,U+d759,U+f981}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.80.woff2?v=3802ad32c6c1") format('woff2-variations');unicode-range:U+e0,U+e2,U+395,U+3b7,U+3ba,U+2460-2461,U+25a0,U+3010-3011,U+306e,U+30f3,U+314a,U+314c,U+5927,U+65b0,U+7e41,U+97d3,U+9ad4,U+ad49,U+ae0b,U+ae0d,U+ae43,U+ae5d,U+aecf,U+af3c,U+af64,U+afd4,U+b080,U+b084,U+b0c5,U+b10c,U+b1e8,U+b2ac,U+b36e,U+b451,U+b515,U+b540,U+b561,U+b6ab,U+b6b1,U+b72c,U+b730,U+b744,U+b800,U+b8ec,U+b8f0,U+b904,U+b968,U+b96d,U+b987,U+b9d9,U+bb36,U+bb49,U+bc2d,U+bc43,U+bcf6,U+bd89,U+be57,U+be61,U+bed4,U+c090,U+c130,U+c148,U+c19c,U+c2f9,U+c36c,U+c37c,U+c384,U+c3df,U+c575,U+c584,U+c660,U+c719,U+c816,U+ca4d,U+ca54,U+cabc,U+cb49,U+cc14,U+cff5,U+d004,U+d038,U+d0b4,U+d0d3,U+d0e0,U+d0ed,U+d131,U+d1b0,U+d31f,U+d33d,U+d3a0,U+d3ab,U+d514,U+d584,U+d6a1,U+d6cc,U+d749,U+d760,U+d799}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.81.woff2?v=f0ae631ec332") format('woff2-variations');unicode-range:U+24,U+60,U+3b9,U+3bb,U+3bd,U+2191,U+2606,U+300c-300d,U+3131,U+3134,U+3139,U+3141-3142,U+3148,U+3161,U+3163,U+321c,U+4eba,U+5317,U+ac31,U+ac77,U+ac9f,U+acb9,U+acf0-acf1,U+acfd,U+ad73,U+af3d,U+b00c,U+b04a,U+b057,U+b0c4,U+b188,U+b1cc,U+b214,U+b2db,U+b2ee,U+b304,U+b4ed,U+b518,U+b5bc,U+b625,U+b69c-b69d,U+b7ac,U+b801,U+b86c,U+b959,U+b95c,U+b985,U+ba48,U+bb58,U+bc0c,U+bc38,U+bc85,U+bc9a,U+bf40,U+c068,U+c0bd,U+c0cc,U+c12f,U+c149,U+c1e0,U+c22b,U+c22d,U+c250,U+c2fc,U+c300,U+c313,U+c370,U+c3d8,U+c557,U+c580,U+c5e3,U+c62e,U+c634,U+c6f0,U+c74d,U+c783,U+c78e,U+c796,U+c7bc,U+c92c,U+ca4c,U+cc1c,U+cc54,U+cc59,U+ce04,U+cf30,U+cfc4,U+d140,U+d321,U+d38c,U+d399,U+d54f,U+d587,U+d5d0,U+d6e8,U+d770}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.82.woff2?v=493e29967aa5") format('woff2-variations');unicode-range:U+d7,U+ea,U+fc,U+2192,U+25bc,U+3000,U+3137,U+3145,U+315c,U+7f8e,U+ac13,U+ac71,U+ac90,U+acb8,U+ace7,U+ad7f,U+ae50,U+aef4,U+af34,U+afbc,U+b048,U+b09a,U+b0ad,U+b0bc,U+b113,U+b125,U+b141,U+b20c,U+b2d9,U+b2ed,U+b367,U+b369,U+b374,U+b3cb,U+b4ec,U+b611,U+b760,U+b81b,U+b834,U+b8b0,U+b8e1,U+b989,U+b9d1,U+b9e1,U+b9fa,U+ba4d,U+ba78,U+bb35,U+bb54,U+bbf9,U+bc11,U+bcb3,U+bd05,U+bd95,U+bdd4,U+be10,U+bed0,U+bf51,U+c0d8,U+c232,U+c2b7,U+c2eb,U+c378,U+c500,U+c52c,U+c549,U+c568,U+c598,U+c5c9,U+c61b,U+c639,U+c67c,U+c717,U+c78a,U+c80a,U+c90c-c90d,U+c950,U+c9e7,U+cbe4,U+cca9,U+cce4,U+cdb0,U+ce78,U+ce94,U+ce98,U+cf8c,U+d018,U+d034,U+d0f1,U+d1b1,U+d280,U+d2f8,U+d338,U+d380,U+d3b4,U+d610,U+d69f,U+d6fc,U+d758}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.83.woff2?v=f8f1fe652aaf") format('woff2-variations');unicode-range:U+e7,U+2022,U+203b,U+25c0,U+2605,U+2661,U+3147,U+318d,U+672c,U+8a9e,U+acaa,U+acbc,U+ad1c,U+ae4a,U+ae5c,U+b044,U+b054,U+b0c8-b0c9,U+b2a6,U+b2d0,U+b35c,U+b364,U+b428,U+b454,U+b465,U+b4b7,U+b4e3,U+b51c,U+b5a1,U+b784,U+b790,U+b7ab,U+b7f4,U+b82c,U+b835,U+b8e9,U+b8f8,U+b9d8,U+b9f9,U+ba5c,U+ba64,U+babd,U+bb18,U+bb3b,U+bbff,U+bc0d,U+bc45,U+bc97,U+bcbc,U+be45,U+be75,U+be7c,U+bfcc,U+c0b6,U+c0f7,U+c14b,U+c2b4,U+c30d,U+c4f8,U+c5bb,U+c5d1,U+c5e0,U+c5ee,U+c5fd,U+c606,U+c6c5,U+c6e0,U+c708,U+c81d,U+c820,U+c824,U+c878,U+c918,U+c96c,U+c9e4,U+c9f1,U+cc2e,U+cd09,U+cea1,U+cef5,U+cef7,U+cf64,U+cf69,U+cfe8,U+d035,U+d0ac,U+d230,U+d234,U+d2f4,U+d31d,U+d575,U+d578,U+d608,U+d614,U+d718,U+d751,U+d761,U+d78c,U+d790}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.84.woff2?v=d28ace2d199c") format('woff2-variations');unicode-range:U+2665,U+3160,U+4e2d,U+6587,U+65e5,U+ac12,U+ac14,U+ac16,U+ac81,U+ad34,U+ade0,U+ae54,U+aebc,U+af2c,U+afc0,U+afc8,U+b04c,U+b08c,U+b099,U+b0a9,U+b0ac,U+b0ae,U+b0b8,U+b123,U+b179,U+b2e5,U+b2f7,U+b4c0,U+b531,U+b538,U+b545,U+b550,U+b5a8,U+b6f0,U+b728,U+b73b,U+b7ad,U+b7ed,U+b809,U+b864,U+b86d,U+b871,U+b9bf,U+b9f5,U+ba40,U+ba4b,U+ba58,U+ba87,U+baac,U+bbc0,U+bc16,U+bc34,U+bd07,U+bd99,U+be59,U+bfd0,U+c058,U+c0e4,U+c0f5,U+c12d,U+c139,U+c228,U+c529,U+c5c7,U+c635,U+c637,U+c735,U+c77d,U+c787,U+c789,U+c8c4,U+c989,U+c98c,U+c9d0,U+c9d3,U+cc0c,U+cc99,U+cd0c,U+cd2c,U+cd98,U+cda4,U+ce59,U+ce60,U+ce6d,U+cea0,U+d0d0-d0d1,U+d0d5,U+d14d,U+d1a4,U+d29c,U+d2f1,U+d301,U+d39c,U+d3bc,U+d4e8,U+d540,U+d5ec,U+d640,U+d750}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.85.woff2?v=757b9fc85ad8") format('woff2-variations');unicode-range:U+5e,U+25b2,U+25b6,U+314e,U+ac24,U+ace1,U+ace4,U+ae68,U+af2d,U+b0d0,U+b0e5,U+b150,U+b155,U+b193,U+b2c9,U+b2dd,U+b3c8,U+b3fc,U+b410,U+b458,U+b4dd,U+b5a0,U+b5a4,U+b5bb,U+b7b5,U+b838,U+b840,U+b86f,U+b8f9,U+b960,U+b9e5,U+bab8,U+bb50,U+bc1d,U+bc24-bc25,U+bca8,U+bcbd,U+bd04,U+bd10,U+bd24,U+be48,U+be5b,U+be68,U+c05c,U+c12c,U+c140,U+c15c,U+c168,U+c194,U+c219,U+c27d,U+c2a8,U+c2f1,U+c2f8,U+c368,U+c554-c555,U+c559,U+c564,U+c5d8,U+c5fc,U+c625,U+c65c,U+c6b1,U+c728,U+c794,U+c84c,U+c88c,U+c8e0,U+c8fd,U+c998,U+c9dd,U+cc0d,U+cc30,U+ceec,U+cf13,U+cf1c,U+cf5c,U+d050,U+d07c,U+d0a8,U+d134,U+d138,U+d154,U+d1f4,U+d2bc,U+d329,U+d32c,U+d3d0,U+d3f4,U+d3fc,U+d56b,U+d5cc,U+d600-d601,U+d639,U+d6c8,U+d754,U+d765}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.86.woff2?v=3e680901e55f") format('woff2-variations');unicode-range:U+3c-3d,U+2026,U+24d2,U+314b,U+ac11,U+acf3,U+ad74,U+ad81,U+adf9,U+ae34,U+af43,U+afb8,U+b05d,U+b07c,U+b110,U+b118,U+b17c,U+b180,U+b18d,U+b192,U+b2cc,U+b355,U+b378,U+b4a4,U+b4ef,U+b78d,U+b799,U+b7a9,U+b7fd,U+b807,U+b80c,U+b839,U+b9b4,U+b9db,U+ba3c,U+bab0,U+bba4,U+bc94,U+be4c,U+c154,U+c1c4,U+c26c,U+c2ac,U+c2ed,U+c4f4,U+c55e,U+c561,U+c571,U+c5b5,U+c5c4,U+c654-c655,U+c695,U+c6e8,U+c6f9,U+c724,U+c751,U+c775,U+c7a0,U+c7c1,U+c874,U+c880,U+c9d5,U+c9f8,U+cabd,U+cc29,U+cc2c,U+cca8,U+ccab,U+ccd0,U+ce21,U+ce35,U+ce7c,U+ce90,U+cee8,U+cef4,U+cfe0,U+d070,U+d0b9,U+d0c1,U+d0c4,U+d0c8,U+d15c,U+d1a1,U+d2c0,U+d300,U+d314,U+d3ed,U+d478,U+d480,U+d48d,U+d508,U+d53d,U+d5e4,U+d611,U+d61c,U+d68d,U+d6a8,U+d798}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.87.woff2?v=04ca8277cfe3") format('woff2-variations');unicode-range:U+23,U+25,U+5f,U+a9,U+ac08,U+ac78,U+aca8,U+acac,U+ace8,U+ad70,U+adc0,U+addc,U+b137,U+b140,U+b208,U+b290,U+b2f5,U+b3c5,U+b3cc,U+b420,U+b429,U+b529,U+b530,U+b77d,U+b79c,U+b7a8,U+b7c9,U+b7f0,U+b7fc,U+b828,U+b860,U+b9ad,U+b9c1,U+b9c9,U+b9dd-b9de,U+b9e8,U+ba38-ba39,U+babb,U+bc00,U+bc8c,U+bca0,U+bca4,U+bcd1,U+bcfc,U+bd09,U+bdf0,U+be60,U+c0ad,U+c0b4,U+c0bc,U+c190,U+c1fc,U+c220,U+c288,U+c2b9,U+c2f6,U+c528,U+c545,U+c558,U+c5bc,U+c5d4,U+c600,U+c644,U+c6c0,U+c6c3,U+c721,U+c798,U+c7a1,U+c811,U+c838,U+c871,U+c904,U+c990,U+c9dc,U+cc38,U+cc44,U+cca0,U+cd1d,U+cd95,U+cda9,U+ce5c,U+cf00,U+cf58,U+d150,U+d22c,U+d305,U+d328,U+d37c,U+d3f0,U+d551,U+d5a5,U+d5c8,U+d5d8,U+d63c,U+d64d,U+d669,U+d734,U+d76c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.88.woff2?v=192abc4c6ad9") format('woff2-variations');unicode-range:U+26,U+2b,U+3e,U+40,U+7e,U+ac01,U+ac19,U+ac1d,U+aca0,U+aca9,U+acb0,U+ad8c,U+ae09,U+ae38,U+ae40,U+aed8,U+b09c,U+b0a0,U+b108,U+b204,U+b298,U+b2d8,U+b2eb-b2ec,U+b2f4,U+b313,U+b358,U+b450,U+b4e0,U+b54c,U+b610,U+b780,U+b78c,U+b791,U+b8e8,U+b958,U+b974,U+b984,U+b9b0,U+b9bc-b9bd,U+b9ce,U+ba70,U+bbfc,U+bc0f,U+bc15,U+bc1b,U+bc31,U+bc95,U+bcc0,U+bcc4,U+bd81,U+bd88,U+c0c8,U+c11d,U+c13c,U+c158,U+c18d,U+c1a1,U+c21c,U+c4f0,U+c54a,U+c560,U+c5b8,U+c5c8,U+c5f4,U+c628,U+c62c,U+c678,U+c6cc,U+c808,U+c810,U+c885,U+c88b,U+c900,U+c988,U+c99d,U+c9c8,U+cc3d-cc3e,U+cc45,U+cd08,U+ce20,U+cee4,U+d074,U+d0a4,U+d0dd,U+d2b9,U+d3b8,U+d3c9,U+d488,U+d544,U+d559,U+d56d,U+d588,U+d615,U+d648,U+d655,U+d658,U+d65c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.89.woff2?v=44634e793e0d") format('woff2-variations');unicode-range:U+d,U+7c,U+ac10,U+ac15,U+ac74,U+ac80,U+ac83,U+acc4,U+ad11,U+ad50,U+ad6d,U+adfc,U+ae00,U+ae08,U+ae4c,U+b0a8,U+b124,U+b144,U+b178,U+b274,U+b2a5,U+b2e8,U+b2f9,U+b354,U+b370,U+b418,U+b41c,U+b4f1,U+b514,U+b798,U+b808,U+b824-b825,U+b8cc,U+b978,U+b9d0,U+b9e4,U+baa9,U+bb3c,U+bc18,U+bc1c,U+bc30,U+bc84,U+bcf5,U+bcf8,U+bd84,U+be0c,U+be14,U+c0b0,U+c0c9,U+c0dd,U+c124,U+c2dd,U+c2e4,U+c2ec,U+c54c,U+c57c-c57d,U+c591,U+c5c5-c5c6,U+c5ed,U+c608,U+c640,U+c6b8,U+c6d4,U+c784,U+c7ac,U+c800-c801,U+c9c1,U+c9d1,U+cc28,U+cc98,U+cc9c,U+ccad,U+cd5c,U+cd94,U+cd9c,U+cde8,U+ce68,U+cf54,U+d0dc,U+d14c,U+d1a0,U+d1b5,U+d2f0,U+d30c,U+d310,U+d398,U+d45c,U+d50c,U+d53c,U+d560,U+d568,U+d589,U+d604,U+d6c4,U+d788}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.90.woff2?v=ed2d605d80cb") format('woff2-variations');unicode-range:U+ac04,U+ac1c,U+ac70,U+ac8c,U+acbd,U+acf5,U+acfc,U+ad00,U+ad6c,U+adf8,U+b098,U+b0b4,U+b294,U+b2c8,U+b300,U+b3c4,U+b3d9,U+b4dc,U+b4e4,U+b77c,U+b7ec,U+b85d,U+b97c,U+b9c8,U+b9cc,U+ba54,U+ba74,U+ba85,U+baa8,U+bb34,U+bb38,U+bbf8,U+bc14,U+bc29,U+bc88,U+bcf4,U+bd80,U+be44,U+c0c1,U+c11c,U+c120,U+c131,U+c138,U+c18c,U+c218,U+c2b5,U+c2e0,U+c544,U+c548,U+c5b4,U+c5d0,U+c5ec,U+c5f0,U+c601,U+c624,U+c694,U+c6a9,U+c6b0,U+c6b4,U+c6d0,U+c704,U+c720,U+c73c,U+c740,U+c744,U+c74c,U+c758,U+c77c,U+c785,U+c788,U+c790-c791,U+c7a5,U+c804,U+c815,U+c81c,U+c870,U+c8fc,U+c911,U+c9c4,U+ccb4,U+ce58,U+ce74,U+d06c,U+d0c0,U+d130,U+d2b8,U+d3ec,U+d504,U+d55c,U+d569,U+d574,U+d638,U+d654,U+d68c}@font-face{font-family:'Pretendard Variable';font-style:normal;font-display:swap;font-weight:45 920;src:url("fonts/pretendard/woff2-dynamic-subset/PretendardVariable.subset.91.woff2?v=fc9fcd1bea9c") format('woff2-variations');unicode-range:U+20-22,U+27-2a,U+2c-39,U+3a-3b,U+3f,U+41-4e,U+4f-5d,U+61-7b,U+7d,U+a0-a1,U+ab,U+ad-ae,U+b7,U+bb,U+bf,U+2013-2014,U+201c-201d,U+2122,U+ac00,U+ace0,U+ae30,U+b2e4,U+b85c,U+b9ac,U+c0ac,U+c2a4,U+c2dc,U+c774,U+c778,U+c9c0,U+d558}
/*# sourceMappingURL=/sm/49af798104dba87a942919357f383e653ce9152ba9bdc9bbfa8ba846a1b04235.map */

/* @axe/ui canonical flattened CSS — GENERATED; DO NOT EDIT.
 * source: tokens/index.css → styles/reset.css → styles/components.css import graph
 * regenerate: node scripts/gen-css-bundle.mjs
 */

/* source: tokens/fonts.css */
/* ============================================================
 * AXE Labs — fonts (소비자 채널 — *자체완결* 필수)
 *
 *  Clash Display     : display 자리 — host가 공식 Fontshare API로 opt-in
 *  Pretendard Var.   : 본문 · UI · 라벨          (same-origin dynamic-subset)
 *  Sarasa Fixed K    : 코드 · 터미널 · 박스아트   (self-host woff2)
 *
 *  ⚠ 본 파일은 docs(sync-axe-ui.mjs 파일 단위 복사)·cortex(sync-axe-ui.sh
 *  단일 bundle 연결) 가 *이 파일 하나만* 가져간다 — 상대 @import 분리 금지,
 *  same-origin font CSS import + 자산 복사 계약을 유지한다.
 *
 *  Next 앱 (axelabs.ai/design.axelabs.ai) 은 이 파일을 import 하지 않는다 —
 *  app/fonts-app.css (본 파일과 내용 동기 — 원격 Pretendard @import 제외) +
 *  same-origin Pretendard mirror <link> (app/layout.tsx) 를 사용해
 *  render-blocking third-party @import 체인을 제거. ⚠ @font-face/토큰 변경 시
 *  두 파일을 함께 수정할 것 (colors.css 다크 2블록과 같은 규율).
 *
 *  Sarasa Fixed K subset 재생성: npm run fonts:install
 * ============================================================ */

/* Pretendard — same-origin dynamic-subset. 소비자는 `axe-ui-copy-fonts`로 자산을 복사.
 * (구 D2Coding @import 는 family 명 불일치 'D2 coding' 로 한 번도 매칭된 적
 *  없는 dead code + 1.4MB/weight 잠재 페이로드 — 2026-06-10 제거.) */
/* unicode-range 의도적 미설정 — Sarasa Fixed K 는 ASCII·한글·박스 모두 처리하며,
 * 한글:ASCII 정확히 2:1 너비를 보장하기 위해 영문도 같은 폰트가 그려야 함.
 *
 * 이전엔 unicode-range 명시했으나 CSS minifier 가 `U+1100-11FF` 를 wildcard
 * `u+11??` 로 압축 → Chrome 이 invalid 로 해석 → 전체 @font-face 거부 →
 * 폰트 로딩 실패 → fallback (Menlo) 으로 렌더 → 한글이 1.4× 가변폭 → 박스 깨짐.
 *
 * (이 함정은 dev (next dev, unminified) 에서는 안 보이고 production 빌드에서만
 * 발현되므로 진단 어려움.  unicode-range 없이 두면 모든 글자 매칭 + minifier
 * 가 만질 게 없음.) */
/* Sarasa Fixed K — Regular(400) 만 self-host.
 *
 * Bold(700) 제거 이유:
 *   - 코드/박스/표 의 mono 자리에 bold 거의 안 씀 (decorative 영향 X)
 *   - Cloudflare edge 가 Bold 파일에 transient 503 을 영구 캐시하는 함정 발견
 *     (2026-05-23, docs.axelabs.ai) — Regular 만 200, Bold 만 503 → 페이지
 *     안 `<strong>` 만 fallback (Pretendard Bold) 으로 빠지면서 한글 가변폭
 *     → 박스 안 markdown ** 굵게 라인만 misalign.
 *   - font-weight: 700 시 browser 가 Regular 를 algorithmic-bold 로 그리거나
 *     stack 의 다음 폰트 (Pretendard Bold) 로 fallback — 본문 외 위치라
 *     의미상 무관.
 *
 * unicode-range 도 *의도적 미설정* — minifier 의 wildcard 변환이 Chrome 에서
 * 거부됨 (이전 함정).  Regular 하나만 두면 minifier 가 만질 게 없음.
 *
 * ?v=2 cache-bust — 이 URL 은 carve-out 이전 깨진 응답(HTML/404)이 브라우저에
 * max-age=14400 으로 캐시된 이력이 있음 → FontFace status:error 가 일반
 * 새로고침으로 안 풀림 (2026-06-10 Windows Chrome 실측). 자산 내용이 바뀌면
 * 반드시 v 를 올릴 것 (URL 불변 정책 금지). */
@font-face {
  font-family: "Sarasa Fixed K";
  src: url("fonts/SarasaFixedK-Regular.woff2?v=acc8d96dadf8") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Clash Display는 OFL이 아니라 ITF FFL 대상이다. 본 토큰 파일과 package/
 * Consumer Kit은 서체 바이너리를 배포하지 않는다. Clash가 필요한 host는
 * route-scoped 또는 첫 paint 뒤 client loader가 document.head에 공식 API
 * stylesheet를 삽입한다(500/600 URL):
 * https://api.fontshare.com/v2/css?f[]=clash-display@500,600&display=swap
 * CSS @import는 f[]=가 빌드 파이프라인에서 탈락한 이력이 있어 사용하지 않는다. */

/* ---- zero-CLS: metric-matched 시스템 폴백 ----
 * Pretendard 도착 전 폴백이 같은 줄높이/폭으로 그려져 swap 시 reflow 최소화.
 * Pretendard 는 Apple SD Gothic Neo metrics-호환 설계 (공식 README) —
 * size-adjust 100% + Pretendard 수직 메트릭 (ascent 1060/descent 300/UPM 1000)
 * override 로 사실상 무이동. Malgun (Windows) 은 폭이 살짝 넓어 98% 보정. */
@font-face {
  font-family: "Pretendard Fallback";
  src: local("Apple SD Gothic Neo");
  size-adjust: 100%;
  ascent-override: 106%;
  descent-override: 30%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Pretendard Fallback MG";
  src: local("Malgun Gothic");
  size-adjust: 98%;
  ascent-override: 108%;
  descent-override: 30.5%;
  line-gap-override: 0%;
}

:root {
  /* 본문 / UI / 디스플레이 *공통* sans 스택 — Pretendard 1순위.
   * default 헤딩 페이스도 이걸로 받음 (Clash 는 옵션이므로 강제 X).
   * Fallback 페이스 2종은 metric-matched (위 @font-face) — CLS 억제. */
  --font-sans:
    "Pretendard Variable", Pretendard, "Pretendard Fallback",
    "Pretendard Fallback MG", -apple-system, BlinkMacSystemFont,
    "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;

  /* --font-display = 디스플레이 자리 (h1·h2·card title·logo 등) 의 의미적 슬롯.
   * 현재 sans 와 동일 — 즉 default 는 Pretendard.  옵션 디스플레이 페이스를
   * 적용하고 싶으면 컴포넌트 측에서 var(--font-clash) 또는 다른 토큰을 명시. */
  --font-display: var(--font-sans);

  /* Clash Display *옵션* 슬롯 — "여기는 명시적으로 Clash 로 가고 싶다" 는
   * 자리만 var(--font-clash) 직접 참조. default가 아니며 host가 공식 API로 opt-in. */
  --font-clash: "Clash Display", var(--font-sans);

  /* 브랜드 식자 단일 슬롯. Clash 미로딩 소비자는 Pretendard로 안전 폴백. */
  --font-brand: "Clash Display", var(--font-sans);

  /* Sarasa Fixed K — 한글이 ASCII 의 정확히 2× 너비. 박스 정렬에 결정적.
   * (구 D2Coding CDN 폴백은 family 명 불일치 'D2 coding' 로 한 번도 매칭된
   *  적 없는 dead code 였음 — 2026-06-10 제거.) */
  --font-mono:
    "Sarasa Fixed K", "JetBrains Mono", "SF Mono", Menlo, Consolas,
    monospace;
}

/* source: tokens/colors.css */
/* ============================================================
 * AXE Labs — colors
 *
 *  - Structure: low-chroma neutral 12-step in both light and dark
 *  - Brand: AXE wine, reserved for identity surfaces
 *  - Accent: clear blue for interaction; phthalo green and scarf orange for state
 *
 *  Step 의미 (Radix scale 패턴 동일):
 *    1  App background          7  UI element border
 *    2  Subtle / elevated bg    8  Hover border / focus
 *    3  UI element bg           9  Solid bg (disabled, placeholder dot)
 *    4  Hover UI bg            10  Hover solid
 *    5  Active UI bg           11  Low-contrast text  (caption)
 *    6  Subtle border, divider 12  High-contrast text (body)
 *
 *  ── 다크 팔레트 = light-dark() 단일 선언 (2026-07 Astryx 채굴 리팩터) ──
 *  이전엔 다크 값이 세 곳([data-theme=dark]/.dark 블록 + prefers-color-scheme
 *  미디어 블록)에 byte-identical 로 중복 선언돼 있었고, 그 수동 동기화가
 *  2026-06-10 gray-8/9/10 drift 사고(두 블록 값 불일치 + ramp 단조성 붕괴)를
 *  낳았다. 이제 토큰당 `light-dark(<라이트>, <다크>)` 한 줄로 접어 중복 자체를
 *  제거 — 두 값이 물리적으로 한 곳에 있어 drift 가 불가능하다.
 *
 *  모드 전환은 CSS `color-scheme` 로 한다 (light-dark() 는 요소의 계산된
 *  color-scheme 에 따라 라이트/다크 인자를 고른다):
 *    :root                         → color-scheme: light dark  (OS 기본 따라감)
 *    [data-theme=dark] / .dark     → color-scheme: dark        (명시 다크)
 *    [data-theme=light] / .light   → color-scheme: light       (명시 라이트)
 *  data-theme 토글·.light/.dark 클래스(next-themes)·prefers-color-scheme
 *  자동 — 세 경로 모두 리팩터 전과 각 토큰 해석값이 완전 동일하다
 *  (resolve_tokens.py 4-state 등가 증명).
 *
 *  ⚠ 브라우저 지원: light-dark() (color) = Baseline 2024-05 — Chrome/Edge 123+,
 *  Safari 17.5+, Firefox 120+ (2026-07-10 정정: 종전 'Chrome/Edge 110+' 는 오기).
 *  미지원 브라우저는 전 색 토큰이 invalid-at-computed-value → 무브랜드 렌더.
 *  '내부 도구 대상' 전제는 소비자에 따라 성립하지 않는다(layer viewer/gate 는
 *  외부 수신자 표면) — 외부 서빙 소비자는 폴백 필수. layer 는 번들 시
 *  @supports not (color: light-dark(#000,#fff)) 라이트 정적값 블록을 자동
 *  생성한다(assets/axe-ui/build_bundle.py). light-dark() 미지원 표면(구형
 *  이메일 클라이언트 등)에는 이 토큰을 직접 흘리지 말 것 — 값을 인라인/구운다.
 * ============================================================ */

/* -------- 모드 스위치 (color-scheme) --------
 * 두 토글 전략 모두 지원:
 *   - data-theme="light|dark"  (axelabs 메인 앱 + 직접 토글)
 *   - .light / .dark           (next-themes class 기본값 — Nextra docs 등)
 * :root 에 `light dark` 를 둬 명시 선택이 없으면 prefers-color-scheme 를
 * 따르게 하고, 명시 선택 시 단일 스킴으로 좁힌다. */
:root {
  color-scheme: light dark;
}
[data-theme="dark"],
.dark {
  color-scheme: dark;
}
[data-theme="light"],
.light {
  color-scheme: light;
}

/* -------- 토큰 (light-dark(<라이트>, <다크>)) --------
 * 라이트와 다크 모두 구조층은 거의 무채색이다. 브랜드·상태색이 surface tint를
 * 소유하지 않게 해 장시간 쓰는 업무 화면의 밀도와 테마 연속성을 맞춘다. */
:root {
  /* Active palette. Dark arms are luminance-tuned for AA on elevated #2d2d2d. */
  --brand-claret: light-dark(#821f3b, #d2839a);
  --brand-claret-print: #821f3b;
  --palette-green: light-dark(#00523f, #5dad95);
  --palette-blue: light-dark(#104a70, #5aa5d2);
  --palette-orange: light-dark(#9b562e, #ea8d56);

  /* Compatibility roots retained for existing consumers; no longer active palette roles. */
  --brand-noir: #1a0610;
  --brand-neon: #e3ff66;

  /* gray ramp — low-chroma structure, independent from brand and semantic color. */
  --gray-1: light-dark(#f7f7f6, #181818);   /* App background */
  --gray-2: light-dark(#f3f3f2, #202020);   /* Subtle background */
  --gray-3: light-dark(#efefee, #292929);   /* Rail / elevated foundation */
  --gray-4: light-dark(#e9e9e8, #2d2d2d);
  --gray-5: light-dark(#e4e4e2, #333333);
  --gray-6: light-dark(#dcdcd9, #393939);
  --gray-7: light-dark(#d5d5d2, #414141);
  --gray-8: light-dark(#b8b8b4, #575757);
  --gray-9: light-dark(#8a8a86, #737373);
  --gray-10: light-dark(#686865, #979797);  /* text-tertiary — elevated 표면 대비 AA */
  --gray-11: light-dark(#4b4b48, #b5b5b5);
  --gray-12: light-dark(#20201e, #f2f2f2);

  --bg-base: var(--gray-1);
  --bg-subtle: var(--gray-2);
  --bg-elevated: light-dark(#ffffff, var(--gray-4));
  --bg-overlay: light-dark(rgb(32 32 30 / 0.55), rgb(0 0 0 / 0.68));

  --text-primary: var(--gray-12);
  --text-secondary: var(--gray-11);
  --text-tertiary: var(--gray-10);
  /* muted도 UI 본문/placeholder에 쓰이므로 양 모드·elevated 표면에서 4.5:1 이상. */
  --text-muted: var(--gray-10);
  --text-inverse: var(--gray-1);

  /* Neutral alpha ink composes consistently across base, rail, and elevated surfaces. */
  --border-subtle: light-dark(rgb(32 32 30 / 0.12), rgb(255 255 255 / 0.12));
  --border-default: light-dark(rgb(32 32 30 / 0.17), rgb(255 255 255 / 0.18));
  --border-strong: light-dark(rgb(32 32 30 / 0.29), rgb(255 255 255 / 0.27));
  /* 입력·버튼처럼 경계 자체가 식별 단서인 control 전용(표면 대비 ≥3:1). */
  --border-control: light-dark(rgb(32 32 30 / 0.48), rgb(255 255 255 / 0.40));
  --border-control-hover: light-dark(#8a8a86, #797979);

  /* accent = functional interaction blue, independent from AXE wine identity.
   * 다음 자리에 사용:
   *   - Prose 링크 · Input/ChatInput focus border(+accent-soft 링)
   *   - Card 인터랙티브 hover 보더 · Badge "accent" · Callout 좌보더
   *   - ToolCall 이름 색 · ::selection 배경 · :focus-visible outline
   * Primary CTA 는 별도 --cta (행동 자리는 의미 부담 없는 ink). */
  --accent: var(--palette-blue);
  --accent-hover: light-dark(#0c3c5b, #82bce0);
  --accent-fg: light-dark(#ffffff, #181818);
  --accent-soft: light-dark(rgb(16 74 112 / 0.10), rgb(90 165 210 / 0.14));

  /* cta = Primary 버튼 등 행동 자리. 모드 따라 ink 인버전 (Vercel · Linear ·
   * Anthropic 의 black/cream CTA 패턴). 양 모드 모두 gray-12/11/1 참조라
   * 선언은 동일하지만, 밑단 gray 가 light-dark 라 자동 flip. */
  --cta: var(--gray-12);
  --cta-hover: var(--gray-11);
  --cta-fg: var(--gray-1);

  --success: var(--palette-green);
  --warning: var(--palette-orange);
  --danger: light-dark(#c4321f, #f26a55);
  --info: var(--palette-blue);

  /* 상태 soft 배경 — 구조 ramp와 분리된 bounded semantic tint. */
  --success-soft: light-dark(#e5f1ed, #203b34);
  --warning-soft: light-dark(#f4e9e1, #463329);
  --danger-soft: light-dark(#fbe7e2, rgb(242 106 85 / 0.10));
  --info-soft: light-dark(#e7f0f5, #213746);

  /* elevation (라이트) — 2-layer 레시피 (key light + ambient), neutral ink.
   *
   * ⚠ shadow 는 <color> 가 아니라 shadow-list(콤마 포함) 라 light-dark() 로 접을
   *   수 없다 (light-dark 는 <color>|<image> 전용, CSS Color L5). 따라서 다크
   *   그림자는 아래 별도 블록에서 **한 번만** 선언한다 — 명시 [data-theme=dark]/
   *   .dark 와 OS prefers-dark 를 하나의 selector-list 로 묶어, 종전의
   *   byte-identical 이중 선언(drift 원인) 을 제거했다. */
  --shadow-xs: 0 1px 2px rgb(32 32 30 / 0.05);
  --shadow-sm: 0 1px 2px rgb(32 32 30 / 0.05), 0 2px 6px -1px rgb(32 32 30 / 0.05);
  --shadow-md: 0 2px 4px rgb(32 32 30 / 0.04), 0 8px 20px -6px rgb(32 32 30 / 0.10);
  --shadow-lg: 0 4px 8px rgb(32 32 30 / 0.05), 0 20px 48px -12px rgb(32 32 30 / 0.16);
  --shadow-xl: 0 8px 16px rgb(32 32 30 / 0.06), 0 32px 80px -16px rgb(32 32 30 / 0.22);

  /* focus ring — 선명한 2px 핵심선 + 3px soft halo의 SSOT.
   * accent/danger와 각 soft 토큰이 light-dark라 링도 모드 자동 flip. */
  --ring: 0 0 0 2px var(--accent), 0 0 0 5px var(--accent-soft);
  --ring-danger: 0 0 0 2px var(--danger), 0 0 0 5px var(--danger-soft);
}

/* -------- elevation (다크) --------
 * 순검정 드롭 섀도에 흰 inset 림 한 겹(inset 0 0 0 1px rgb(255 255 255 / 0.08))
 * 을 추가 (2026-07 Astryx/Figma bezel 기법): 다크 기본 표면에서 카드·드로어·
 * 모달의 엣지를 살짝 띄워 리프팅을 강화. 드롭 섀도 geometry/알파는 리팩터 전과
 * 동일 — inset 림만 신규.
 *
 * ⚠ shadow 는 <color> 가 아니라 shadow-list(콤마 포함) 라 light-dark() 로 접을
 *   수 없다 (light-dark = <color>|<image> 전용, CSS Color L5). 색 팔레트와 달리
 *   다크 그림자는 아래 두 컨텍스트(명시 .dark/[data-theme=dark] + OS prefers-dark)
 *   에 동일 값이 반복될 수밖에 없다 — 순수 CSS 로는 at-rule 을 selector-list 에
 *   넣지 못하기 때문. 두 블록 값은 반드시 동일하게 유지(색 토큰과 달리 shadow
 *   drift 는 지각 영향이 작지만, 바꿀 땐 두 곳을 함께 바꿀 것).
 *   `--shadow-inset-rim` 를 한 곳에서 정의해 두 블록이 그 변수를 공유 → inset 림
 *   값만큼은 SoT 를 단일화(림 두께/알파 변경 시 한 줄만 수정). */
:root {
  --shadow-inset-rim: inset 0 0 0 1px rgb(255 255 255 / 0.08);
}
[data-theme="dark"],
.dark {
  --shadow-xs: 0 1px 2px rgb(0 0 0 / 0.40), var(--shadow-inset-rim);
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.45), 0 2px 8px -2px rgb(0 0 0 / 0.50), var(--shadow-inset-rim);
  --shadow-md: 0 2px 4px rgb(0 0 0 / 0.40), 0 10px 24px -6px rgb(0 0 0 / 0.55), var(--shadow-inset-rim);
  --shadow-lg: 0 4px 8px rgb(0 0 0 / 0.45), 0 24px 56px -12px rgb(0 0 0 / 0.65), var(--shadow-inset-rim);
  --shadow-xl: 0 8px 16px rgb(0 0 0 / 0.50), 0 40px 96px -16px rgb(0 0 0 / 0.70), var(--shadow-inset-rim);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not(.light) {
    --shadow-xs: 0 1px 2px rgb(0 0 0 / 0.40), var(--shadow-inset-rim);
    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.45), 0 2px 8px -2px rgb(0 0 0 / 0.50), var(--shadow-inset-rim);
    --shadow-md: 0 2px 4px rgb(0 0 0 / 0.40), 0 10px 24px -6px rgb(0 0 0 / 0.55), var(--shadow-inset-rim);
    --shadow-lg: 0 4px 8px rgb(0 0 0 / 0.45), 0 24px 56px -12px rgb(0 0 0 / 0.65), var(--shadow-inset-rim);
    --shadow-xl: 0 8px 16px rgb(0 0 0 / 0.50), 0 40px 96px -16px rgb(0 0 0 / 0.70), var(--shadow-inset-rim);
  }
}

/* source: tokens/typography.css */
/* ============================================================
 * AXE Labs — typography
 *
 *  스케일 — 16 px base, ±10% 컴파운딩 (ratio 1.1 / 0.9).
 *  큰 헤딩 (3xl/4xl/5xl) 만 `clamp()` 로 모바일 자동 축소 —
 *  본문은 16 px 변동 없음 (한글 가독성 표준).
 *
 *    text-xs    12.96 px   (16 × 0.9²)        고정
 *    text-sm    14.4  px   (16 × 0.9)         고정
 *    text-base  16    px                       고정  <-- 본문
 *    text-lg    17.6  px   (16 × 1.1)         고정
 *    text-xl    19.36 px   (16 × 1.1²)        고정
 *    text-2xl   21.30 px   (16 × 1.1³)        고정
 *    text-3xl   19.36~23.43 px (mobile~desktop)   <-- clamp
 *    text-4xl   21.30~25.77 px (mobile~desktop)   <-- clamp
 *    text-5xl   23.43~28.34 px (mobile~desktop)   <-- clamp  <-- Hero
 *
 *  Clamp 공식: 모바일 (375vw) 에서 한 단계 아래 토큰값까지 내려가고,
 *  데스크탑 (1280vw) 에서 현행 유지. 그 사이는 선형 보간.
 *
 *  자간 (letter-spacing)
 *    본문      0
 *    UI label  0
 *    헤딩     -0.015em      (한·영 모두 안전)
 *    숫자(tabular) 0  + variant-numeric: tabular-nums
 *
 *  줄높이 (line-height)
 *    본문      1.6           (한글 받침 여유)
 *    UI dense  1.5
 *    헤딩 (h3+)1.3
 *    h1/h2     1.15          (display)
 *    code      1.55
 *
 *  Prose 폭 — 680 px (Linear 624 ~ Anthropic 728 의 중간)
 * ============================================================ */

:root {
  /* 본문 인근 — 고정 (모바일/데스크탑 동일). */
  --text-xs: 0.81rem; /*    12.96 px  (16 × 0.9²) */
  --text-sm: 0.9rem; /*     14.4  px  (16 × 0.9) */
  --text-base: 1rem; /*     16    px  <-- 본문 (고정) */
  --text-lg: 1.1rem; /*     17.6  px  (16 × 1.1) */
  --text-xl: 1.21rem; /*    19.36 px  (16 × 1.1²) */
  --text-2xl: 1.331rem; /*  21.30 px  (16 × 1.1³) */

  /* 큰 헤딩 — fluid clamp(min, preferred, max).
   * 모바일 (≤ 375 px) 에선 min 으로 클램프되어 한 단계 아래 토큰값까지 down,
   * 데스크탑 (≥ 1280 px) 에선 max 로 클램프되어 현행 사이즈 유지. */
  --text-3xl: clamp(1.21rem,   1.104rem + 0.45vw,   1.4641rem); /* 19.36 ~ 23.43 px */
  --text-4xl: clamp(1.331rem,  1.216rem + 0.49vw,   1.6105rem); /* 21.30 ~ 25.77 px */
  --text-5xl: clamp(1.4641rem, 1.337rem + 0.5425vw, 1.7716rem); /* 23.43 ~ 28.34 px  <-- Hero */

  /* display 티어 — hero·랜딩 전용, 본문 스케일과 분리 (additive, 기존 --text-* 불변).
   * ±10% 컴파운딩 스케일은 문서·UI 밀도용이라 28px 에서 끝남 — 랜딩 hero 는
   * 별도 등급 필요 (Linear ~64px, Stripe ~90px 급 디스플레이 타입). */
  --text-display-sm: clamp(2rem, 1.55rem + 1.9vw, 3rem);   /* 32 ~ 48 px */
  --text-display-md: clamp(2.5rem, 1.84rem + 2.8vw, 4rem); /* 40 ~ 64 px */
  --text-display-lg: clamp(3rem, 2.06rem + 4vw, 5rem);     /* 48 ~ 80 px */
  --tracking-display: -0.03em; /* display 사이즈 전용 — 한글 혼용 안전 범위 */
  --leading-display: 1.05;

  /* 줄높이 */
  --leading-tight: 1.15;
  --leading-heading: 1.3;
  --leading-normal: 1.5;
  --leading-body: 1.6;
  --leading-code: 1.55;
  --leading-relaxed: 1.75;

  /* 자간 */
  --tracking-tighter: -0.025em;
  --tracking-heading: -0.015em;
  --tracking-normal: 0;
  --tracking-wide: 0.02em;
  --tracking-widest: 0.08em;

  /* 두께 (variable font axis) */
  --weight-light: 300;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;

  /* 폭 */
  --prose-max: 42.5rem; /* 680 px */
  --content-max: 75rem; /* 1200 px */
}

/* 기본 본문 — 어떤 페이지에서도 보장되는 baseline */
html {
  font-size: 16px;
  /* 한국어 본문의 어절 단위 줄바꿈 — Toss/Daangn 패턴 */
  word-break: keep-all;
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-normal);
  color: var(--text-primary);
  background: var(--bg-base);
  font-weight: var(--weight-regular);
}

/* 표 / 숫자 행렬 — 등폭 숫자 + 마이너스 표시 정렬 */
table,
.tabular-nums {
  font-variant-numeric: tabular-nums;
}

/* source: tokens/spacing.css */
/* ============================================================
 * AXE Labs — spacing / radius / motion
 *
 *  4-grid (Linear, Vercel 표준) — 8 단계
 * ============================================================ */

:root {
  /* spacing */
  --space-0: 0;
  --space-1: 0.25rem; /*  4 px */
  --space-2: 0.5rem; /*   8 px */
  --space-3: 0.75rem; /* 12 px */
  --space-4: 1rem; /*    16 px */
  --space-5: 1.5rem; /*  24 px */
  --space-6: 2rem; /*    32 px */
  --space-7: 3rem; /*    48 px */
  --space-8: 4rem; /*    64 px */
  --space-9: 6rem; /*    96 px */
  --space-10: 8rem; /*  128 px */

  /* radius */
  --radius-xs: 2px;
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 10px;
  --radius-xl: 16px;
  --radius-2xl: 24px;
  --radius-full: 9999px;

  /* motion */
  --duration-fast: 120ms;
  --duration-base: 180ms;
  --duration-slow: 280ms;
  --duration-slower: 480ms; /* 진입 reveal · 큰 표면 전환 전용 */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  /* spring — 살짝 overshoot 하는 스냅 (segmented control thumb, 토글,
   * hover lift 류 마이크로 인터랙션). transform 전용으로 쓸 것. */
  --ease-spring: cubic-bezier(0.22, 1.36, 0.36, 1);

  /* z-index */
  --z-base: 1;
  --z-sticky: 100;
  --z-overlay: 1000;
  --z-modal: 1100;
  --z-toast: 1200;
}

/* source: tokens/index.css */
/* AXE Labs design tokens — 단일 import 진입점 */

/* source: styles/reset.css */
/* ============================================================
 * AXE Labs — minimal reset
 *
 * 토큰 파일이 html/body 의 폰트·컬러·줄높이를 이미 잡으므로,
 * 이 파일은 여백·박스모델·기본 element 정상화만.
 * ============================================================ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

/* anchor 네비 부드럽게 — reduced-motion 환경은 아래 media query 가 auto 로 되돌림 */
html {
  scroll-behavior: smooth;
}

/* 헤딩 / 단락 / 리스트 / blockquote 의 기본 여백 제거.
 * 컴포넌트 / Prose 가 명시적으로 spacing 을 부여. */
h1,
h2,
h3,
h4,
h5,
h6,
p,
ul,
ol,
dl,
figure,
blockquote,
pre,
hr {
  margin: 0;
}

/* 리스트 기본 padding 제거 */
ul,
ol {
  padding: 0;
}

/* 이미지 / 미디어 — block, 부모 폭에 맞춤 */
img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

/* form element — 폰트 / 컬러 상속 */
input,
textarea,
select,
button {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

/* [hidden] 강제 — 컴포넌트 CSS 의 display:flex/grid 가 UA 의 [hidden]
 * display:none 을 덮어쓰면 hidden 토글이 시각적으로 무력화됨
 * (실례: .axe-sidebar__group-list 가 flex 라 그룹 접기가 안 먹던 버그,
 * 2026-06-10). until-found 는 검색 가시성 시맨틱이라 제외. */
[hidden]:not([hidden="until-found"]) {
  display: none !important;
}

/* 표 — collapse 기본 + 헤더 정렬 명시 */
table {
  border-collapse: collapse;
  width: 100%;
}

th {
  text-align: left;
  font-weight: var(--weight-semibold, 600);
}

/* 강조 인라인 — italic 의 한글 폴백 정상화 */
i,
em {
  font-style: italic;
  font-feature-settings: "kern";
}

/* 모션 줄이기 환경 — 자동 disable */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* focus 가시성 — 키보드만 (마우스 클릭 시는 끔).
 * border-radius 미지정: outline 은 element 자체 radius 를 따른다 (Chrome 94+).
 * 이전의 border-radius:var(--radius-sm) 은 outline 이 아니라 *element* 의
 * radius 를 덮어써 원형 컨트롤이 Tab 포커스 순간 4px 모서리로 깨지던 버그. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* selection 색 */
::selection {
  background: var(--accent);
  color: var(--accent-fg);
}

/* source: styles/overlays.css */
/* ============================================================
 * @axe/ui — Overlays group  (Toast · Popover · Tooltip)
 *
 *  - 모든 표면은 var(--bg-elevated) + var(--border-subtle) + shadow-md/lg
 *  - 모든 텍스트는 var(--text-primary)/secondary
 *  - 시멘틱 컬러(success/info/warning/danger)는 좌측 인디케이터 보더로만 표현
 *    → 표면 자체는 항상 elevated 톤 유지 (가독성 + 다크/라이트 호환)
 *  - 모든 애니메이션 prefers-reduced-motion 으로 disable
 *  - z-index: tooltip = z-overlay, popover = z-overlay, toast = z-toast
 * ============================================================ */

/* ────────────────────────────────────────────────────────────
 * Toast (sonner)
 *   - sonner 가 [data-sonner-toaster] / [data-sonner-toast] wrapper 를 그림.
 *   - 우리는 classNames prop 으로 .axe-toast / .axe-toast__* 를 주입했고,
 *     sonner 가 만든 내부 markup 까지는 reach 가 어려우니 attribute 셀렉터로 보조.
 *   - --gap, --width 같은 sonner CSS var 도 함께 덮어써서 톤 통일.
 * ──────────────────────────────────────────────────────────── */
[data-sonner-toaster] {
  --normal-bg: var(--bg-elevated);
  --normal-text: var(--text-primary);
  --normal-border: var(--border-subtle);
  --success-bg: var(--bg-elevated);
  --success-text: var(--text-primary);
  --success-border: var(--success);
  --info-bg: var(--bg-elevated);
  --info-text: var(--text-primary);
  --info-border: var(--info);
  --warning-bg: var(--bg-elevated);
  --warning-text: var(--text-primary);
  --warning-border: var(--warning);
  --error-bg: var(--bg-elevated);
  --error-text: var(--text-primary);
  --error-border: var(--danger);
  --gray1: var(--bg-base);
  --gray2: var(--bg-subtle);
  --gray3: var(--border-subtle);
  --gray4: var(--border-default);
  --gray5: var(--border-strong);
  --gray12: var(--text-primary);
  --width: 360px;
  --border-radius: var(--radius-md);
  font-family: var(--font-sans);
  z-index: var(--z-toast);
}

.axe-toast {
  background: var(--bg-elevated) !important;
  color: var(--text-primary) !important;
  border: 1px solid var(--border-subtle) !important;
  border-left-width: 3px !important;
  border-radius: var(--radius-md) !important;
  box-shadow: var(--shadow-md) !important;
  font-family: var(--font-sans) !important;
  font-size: var(--text-sm) !important;
  padding: var(--space-3) var(--space-4) !important;
  gap: var(--space-2) !important;
}

.axe-toast--success { border-left-color: var(--success) !important; }
.axe-toast--info    { border-left-color: var(--info)    !important; }
.axe-toast--warning { border-left-color: var(--warning) !important; }
.axe-toast--danger  { border-left-color: var(--danger)  !important; }
.axe-toast--loading { border-left-color: var(--accent)  !important; }

.axe-toast__title {
  font-weight: var(--weight-semibold) !important;
  color: var(--text-primary) !important;
  font-size: var(--text-sm) !important;
  line-height: 1.4 !important;
}
.axe-toast__description {
  color: var(--text-secondary) !important;
  font-size: var(--text-xs) !important;
  line-height: 1.5 !important;
  margin-top: 2px !important;
}

.axe-toast__action {
  background: var(--cta) !important;
  color: var(--cta-fg) !important;
  border: 0 !important;
  border-radius: var(--radius-sm) !important;
  padding: 4px 10px !important;
  font-size: var(--text-xs) !important;
  font-weight: var(--weight-medium) !important;
  cursor: pointer !important;
}
.axe-toast__action:hover { background: var(--cta-hover) !important; }

.axe-toast__cancel {
  background: transparent !important;
  color: var(--text-secondary) !important;
  border: 1px solid var(--border-subtle) !important;
  border-radius: var(--radius-sm) !important;
  padding: 4px 10px !important;
  font-size: var(--text-xs) !important;
  cursor: pointer !important;
}
.axe-toast__cancel:hover { background: var(--bg-subtle) !important; }

.axe-toast__close {
  background: var(--bg-subtle) !important;
  color: var(--text-tertiary) !important;
  border: 1px solid var(--border-subtle) !important;
  border-radius: var(--radius-full) !important;
}
.axe-toast__close:hover {
  background: var(--bg-base) !important;
  color: var(--text-primary) !important;
}

/* sonner 의 loading spinner — accent 톤으로 */
[data-sonner-toast][data-type="loading"] [data-icon] {
  color: var(--accent) !important;
}

/* ────────────────────────────────────────────────────────────
 * Popover (Radix)
 * ──────────────────────────────────────────────────────────── */
.axe-popover__content {
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: var(--space-3);
  min-width: 200px;
  max-width: min(90vw, 360px);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.5;
  z-index: var(--z-overlay);
  outline: none;
  transform-origin: var(--radix-popover-content-transform-origin);
}
.axe-popover__content[data-state="open"] {
  animation: axe-overlay-in 160ms var(--ease-out);
}
.axe-popover__content[data-state="closed"] {
  animation: axe-overlay-out 120ms ease-in forwards;
}
.axe-popover__content:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.axe-popover__arrow {
  fill: var(--bg-elevated);
  /* Radix Arrow 는 stroke 미지원 — 보더 illusion 은 outer shadow 로 표현 */
  filter: drop-shadow(0 1px 0 var(--border-subtle));
}

/* ────────────────────────────────────────────────────────────
 * Tooltip (Radix)
 *   - Popover 보다 더 작고 더 빠른 트랜지션.
 *   - 단일 라인 ~ 2-3 라인 hint 용.
 * ──────────────────────────────────────────────────────────── */
.axe-tooltip__content {
  background: var(--text-primary);
  color: var(--text-inverse);
  border-radius: var(--radius-sm);
  padding: 6px 10px;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  line-height: 1.4;
  max-width: 280px;
  box-shadow: var(--shadow-md);
  z-index: var(--z-overlay);
  transform-origin: var(--radix-tooltip-content-transform-origin);
  user-select: none;
  pointer-events: none;
}
.axe-tooltip__content[data-state="delayed-open"] {
  animation: axe-overlay-in 120ms var(--ease-out);
}
/* Provider의 skipDelayDuration 안에서 인접 툴팁으로 이동하면 이미 탐색 의도가
 * 분명하다. delay뿐 아니라 재등장 모션도 생략해 toolbar를 즉시 훑게 한다. */
.axe-tooltip__content[data-state="instant-open"] {
  animation: none;
}
.axe-tooltip__content[data-state="closed"] {
  animation: axe-overlay-out 80ms ease-in forwards;
}

.axe-tooltip__arrow {
  fill: var(--text-primary);
}

/* ────────────────────────────────────────────────────────────
 * Shared open/close keyframes (Popover + Tooltip)
 *   - sonner 는 자체 swipe/enter 애니메이션을 가져서 별도로 두지 않음.
 * ──────────────────────────────────────────────────────────── */
@keyframes axe-overlay-in {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes axe-overlay-out {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(0.96); }
}

@media (prefers-reduced-motion: reduce) {
  .axe-popover__content,
  .axe-popover__content[data-state="closed"],
  .axe-tooltip__content,
  .axe-tooltip__content[data-state="closed"],
  .axe-tooltip__content[data-state="delayed-open"],
  .axe-tooltip__content[data-state="instant-open"] {
    animation: none !important;
  }
  /* sonner 자체 트랜지션 비활성화 — data-attr 로 제어 */
  [data-sonner-toast] {
    transition: none !important;
    animation: none !important;
  }
}

/* source: styles/form.css */
/* ============================================================
 * Form group — Select / Checkbox / Radio / Switch / Label / FormField
 *
 * Convention:
 *   - 모든 sizing 은 토큰 (var(--space-*), var(--text-*)).
 *   - focus ring = var(--ring) 토큰 (2px accent core + 3px soft halo)
 *     (Input 과 동일). :focus-visible 만 — 마우스 클릭에 ring 안 뜸.
 *   - error 상태 = border var(--danger) + ring var(--ring-danger).
 *   - 다크/라이트 자동 — CSS var 만 사용.
 *   - prefers-reduced-motion 존중.
 * ============================================================ */

/* ------- Label (axe-label) — Radix Label wrap ------- */
.axe-label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium, 500);
  line-height: 1.4;
  color: var(--text-primary);
  cursor: pointer;
  user-select: none;
}

/* ============================================================
 * Select (axe-select__*) — Radix Select
 * ============================================================ */
.axe-select__trigger {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  height: 36px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-control, var(--border-strong));
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.4;
  text-align: left;
  cursor: pointer;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-select__trigger:hover:not([data-disabled]) {
  border-color: var(--border-control-hover, var(--border-control));
}
.axe-select__trigger:focus-visible,
.axe-select__trigger[data-state="open"] {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-select__trigger[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-select__trigger[data-placeholder] {
  color: var(--text-muted);
}
.axe-select__trigger--lg {
  height: 44px;
  font-size: var(--text-base);
}

/* error wiring — 부모 FormField--error 안 trigger 도 적용 */
.axe-form-field--error .axe-select__trigger {
  border-color: var(--danger);
}
.axe-form-field--error .axe-select__trigger:focus-visible,
.axe-form-field--error .axe-select__trigger[data-state="open"] {
  border-color: var(--danger);
  box-shadow: var(--ring-danger);
}

.axe-select__content {
  min-width: var(--radix-select-trigger-width);
  max-height: var(--radix-select-content-available-height);
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  /* portal 로 body 에 붙는 floating 표면 = overlay 밴드.
   * DropdownMenu·ContextMenu(menus.css)·Popover·Tooltip(overlays.css) 과 같은 값이라
   * Dialog/Sheet(역시 --z-overlay) 안에서 열어도 나중에 portal 되는 쪽이 위에 그려진다.
   * 종전 raw 60 은 sticky chrome(--z-sticky 100) 아래였고, Dialog 가 토큰으로 올라간
   * 뒤에는 패널 뒤로 숨었다. */
  z-index: var(--z-overlay);
  animation: axe-select-in 140ms var(--ease-out, ease-out);
}
.axe-select__content[data-state="closed"] {
  animation: axe-select-out 100ms ease-in forwards;
}
.axe-select__viewport {
  padding: var(--space-1);
}
.axe-select__label {
  padding: var(--space-2) var(--space-3) var(--space-1);
  font-family: var(--font-display);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-widest);
  color: var(--text-tertiary);
}
.axe-select__item {
  position: relative;
  display: flex;
  align-items: center;
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-7);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--text-sm);
  line-height: 1.4;
  cursor: pointer;
  user-select: none;
  outline: none;
}
.axe-select__item[data-highlighted] {
  background: var(--bg-subtle);
}
.axe-select__item[data-state="checked"] {
  color: var(--accent);
  font-weight: var(--weight-medium, 500);
}
.axe-select__item[data-disabled] {
  color: var(--text-muted);
  pointer-events: none;
}
.axe-select__indicator {
  position: absolute;
  left: var(--space-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
}
.axe-select__separator {
  height: 1px;
  margin: var(--space-1) 0;
  background: var(--border-subtle);
}

@keyframes axe-select-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes axe-select-out {
  to { opacity: 0; transform: translateY(-4px); }
}

/* ============================================================
 * Checkbox (axe-checkbox) — Radix Checkbox  +  indeterminate
 * ============================================================ */
.axe-checkbox {
  --size: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--size);
  height: var(--size);
  flex: 0 0 var(--size);
  padding: 0;
  margin: 0;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--border-control, var(--border-strong));
  background: var(--bg-elevated);
  color: var(--accent-fg);
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-checkbox:hover:not([data-disabled]) {
  border-color: var(--accent);
}
.axe-checkbox:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-color: var(--accent);
}
.axe-checkbox[data-state="checked"],
.axe-checkbox[data-state="indeterminate"] {
  background: var(--accent);
  border-color: var(--accent);
}
.axe-checkbox[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* indicator + 두 icon (check / dash) — data-state 로 표시 분기 */
.axe-checkbox__indicator {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}
.axe-checkbox__icon {
  display: none;
  color: var(--accent-fg);
}
.axe-checkbox[data-state="checked"] .axe-checkbox__icon--check {
  display: block;
}
.axe-checkbox[data-state="indeterminate"] .axe-checkbox__icon--dash {
  display: block;
}

/* error wiring */
.axe-form-field--error .axe-checkbox {
  border-color: var(--danger);
}
.axe-form-field--error .axe-checkbox:focus-visible {
  box-shadow: var(--ring-danger);
}
.axe-form-field--error .axe-checkbox[data-state="checked"],
.axe-form-field--error .axe-checkbox[data-state="indeterminate"] {
  background: var(--danger);
  border-color: var(--danger);
}

/* ============================================================
 * Radio (axe-radio__*) — Radix RadioGroup
 * ============================================================ */
.axe-radio__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.axe-radio__item {
  --size: 18px;
  width: var(--size);
  height: var(--size);
  flex: 0 0 var(--size);
  padding: 0;
  margin: 0;
  border-radius: 50%;
  border: 1.5px solid var(--border-control, var(--border-strong));
  background: var(--bg-elevated);
  cursor: pointer;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-radio__item:hover:not([data-disabled]) {
  border-color: var(--accent);
}
.axe-radio__item:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-color: var(--accent);
}
.axe-radio__item[data-state="checked"] {
  border-color: var(--accent);
}
.axe-radio__item[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-radio__indicator {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  position: relative;
}
.axe-radio__indicator::after {
  content: "";
  display: block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

/* error wiring */
.axe-form-field--error .axe-radio__item {
  border-color: var(--danger);
}
.axe-form-field--error .axe-radio__item:focus-visible {
  box-shadow: var(--ring-danger);
}
.axe-form-field--error .axe-radio__item[data-state="checked"] {
  border-color: var(--danger);
}
.axe-form-field--error .axe-radio__indicator::after {
  background: var(--danger);
}

/* ============================================================
 * Switch (axe-switch) — Radix Switch
 * ============================================================ */
.axe-switch {
  --track-w: 36px;
  --track-h: 20px;
  --thumb: 16px;

  position: relative;
  width: var(--track-w);
  height: var(--track-h);
  flex: 0 0 var(--track-w);
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: 999px;
  background: var(--border-control, var(--border-strong));
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-switch:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}
.axe-switch[data-state="checked"] {
  background: var(--accent);
}
.axe-switch[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-switch__thumb {
  display: block;
  width: var(--thumb);
  height: var(--thumb);
  border-radius: 50%;
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  transform: translateX(2px);
  transition: transform var(--duration-fast) var(--ease-out);
  will-change: transform;
}
.axe-switch[data-state="checked"] .axe-switch__thumb {
  transform: translateX(calc(var(--track-w) - var(--thumb) - 2px));
}

/* error wiring */
.axe-form-field--error .axe-switch:focus-visible {
  box-shadow: var(--ring-danger);
}
.axe-form-field--error .axe-switch[data-state="checked"] {
  background: var(--danger);
}

/* ============================================================
 * FormField (axe-form-field) — wrapper layout
 * ============================================================ */
.axe-form-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.axe-form-field__label {
  /* axe-label 상속 — 추가 spacing 만 */
}
.axe-form-field__required {
  color: var(--danger);
  font-weight: var(--weight-medium, 500);
  margin-left: 2px;
}
.axe-form-field__control {
  /* control wrapper — Input/Select/Checkbox 등이 들어옴 */
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.axe-form-field__hint {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--text-tertiary);
}
.axe-form-field__error {
  margin: 0;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--danger);
}
/* error 상태일 때 wrap 안 Input 도 자동 적용 — aria-invalid 가 더 정석이지만
   FormField 의 명시적 error prop 만으로도 시각 동기화 */
.axe-form-field--error .axe-input,
.axe-input[aria-invalid="true"] {
  border-color: var(--danger);
}
.axe-form-field--error .axe-input:focus,
.axe-input[aria-invalid="true"]:focus {
  border-color: var(--danger);
  box-shadow: var(--ring-danger);
}

/* ============================================================
 * Combobox (axe-combobox__*) — 인라인 자동완성 (Popover anchor + listbox)
 *   input = axe-select__trigger 와 동일 sizing/border/ring 토큰,
 *   list/item = axe-cmdk 팝업 토큰 재사용.
 * ============================================================ */
.axe-combobox {
  display: block;
  width: 100%;
}
.axe-combobox__input {
  width: 100%;
  height: 36px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-control, var(--border-strong));
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.4;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-combobox__input::placeholder {
  color: var(--text-muted);
}
.axe-combobox__input:hover:not(:disabled) {
  border-color: var(--border-control-hover, var(--border-control));
}
.axe-combobox__input:focus-visible,
.axe-combobox__input[aria-expanded="true"] {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-combobox__input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-form-field--error .axe-combobox__input {
  border-color: var(--danger);
}
.axe-form-field--error .axe-combobox__input:focus-visible,
.axe-form-field--error .axe-combobox__input[aria-expanded="true"] {
  border-color: var(--danger);
  box-shadow: var(--ring-danger);
}

.axe-combobox__content {
  min-width: var(--radix-popover-trigger-width);
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  z-index: var(--z-overlay); /* .axe-select__content 와 동일한 overlay 밴드 근거 */
}
.axe-combobox__list {
  max-height: 320px;
  overflow-y: auto;
  padding: var(--space-2);
}
.axe-combobox__item {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}
.axe-combobox__item[aria-selected="true"],
.axe-combobox__item:hover {
  background: var(--bg-subtle);
}
.axe-combobox__empty {
  padding: var(--space-6);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* ============================================================
 * Slider (axe-slider__*) — 네이티브 range input + 토큰 채움/thumb.
 *   채움은 --axe-slider-pct(0~100, 컴포넌트가 인라인 주입) → accent 그라데이션.
 *   thumb/track 토큰 = axe-switch/axe-btn 와 동일 accent·ring·border 어휘.
 *   WebKit(::-webkit-slider-*) + Firefox(::-moz-range-*) 양쪽 모두 스타일.
 * ============================================================ */
.axe-slider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
}
.axe-slider__input {
  --axe-slider-pct: 0;
  flex: 1 1 auto;
  min-width: 0;
  height: 20px;
  margin: 0;
  background: transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.axe-slider__input:focus-visible {
  outline: none;
}
/* track — 채운 구간(accent) + 빈 구간(border) 을 한 그라데이션으로 */
.axe-slider__input::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: var(--radius-full);
  background: linear-gradient(
    to right,
    var(--accent) 0%,
    var(--accent) calc(var(--axe-slider-pct) * 1%),
    var(--bg-subtle) calc(var(--axe-slider-pct) * 1%),
    var(--bg-subtle) 100%
  );
}
.axe-slider__input::-moz-range-track {
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--bg-subtle);
}
.axe-slider__input::-moz-range-progress {
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--accent);
}
/* thumb */
.axe-slider__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  margin-top: -5px; /* (16 - 6) / 2 로 track 중앙 정렬 */
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--duration-fast) var(--ease-out);
}
.axe-slider__input::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--duration-fast) var(--ease-out);
}
.axe-slider__input:focus-visible::-webkit-slider-thumb {
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-slider__input:focus-visible::-moz-range-thumb {
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-slider--disabled {
  opacity: 0.5;
}
.axe-slider--disabled .axe-slider__input {
  cursor: not-allowed;
}
.axe-slider__value {
  flex: 0 0 auto;
  min-width: 3ch;
  text-align: right;
  font-family: var(--font-mono, var(--font-sans));
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}

/* ============================================================
 * Calendar (axe-calendar__*) — 단일 날짜 선택 그리드 (dep 0, 순수 CSS).
 *   토큰 어휘 = axe-slider/axe-switch 와 동일 accent·accent-fg·ring·border.
 *   markup 은 role=grid/row/gridcell + 셀별 aria-selected → 서버 렌더(maud/jinja)도
 *   같은 클래스에 aria-selected 만 계산해 넣으면 동일 모양.
 * ============================================================ */
.axe-calendar {
  display: inline-block;
  padding: var(--space-2);
  border: 1px solid var(--border-control, var(--border-strong));
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-size: var(--text-sm);
}
.axe-calendar__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.axe-calendar__title {
  flex: 1 1 auto;
  text-align: center;
  font-weight: 600;
  color: var(--text-primary);
}
.axe-calendar__nav {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--border-control, var(--border-strong));
  border-radius: var(--radius-sm);
  background: var(--bg-base);
  color: var(--text-secondary);
  font-size: var(--text-base);
  line-height: 1;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}
.axe-calendar__nav:hover:not(:disabled) {
  background: var(--bg-subtle);
  border-color: var(--border-control-hover, var(--border-control));
}
.axe-calendar__nav:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-calendar__nav:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-calendar__grid {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.axe-calendar__weekdays,
.axe-calendar__week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}
.axe-calendar__weekday {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 28px;
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-muted);
}
.axe-calendar__day {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}
.axe-calendar__day:hover:not(:disabled):not(.axe-calendar__day--selected) {
  background: var(--bg-subtle);
}
.axe-calendar__day:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-calendar__day--today:not(.axe-calendar__day--selected) {
  border-color: var(--border-control-hover, var(--border-control));
  font-weight: 600;
}
.axe-calendar__day--selected {
  background: var(--accent);
  color: var(--accent-fg);
  font-weight: 600;
}
.axe-calendar__day--selected:hover:not(:disabled) {
  background: var(--accent-hover);
}
.axe-calendar__day:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
/* 이전/다음 달 빈칸 — 클릭 불가 placeholder */
.axe-calendar__day--outside {
  cursor: default;
  pointer-events: none;
}
.axe-calendar--disabled {
  opacity: 0.5;
  pointer-events: none;
}

/* ============================================================
 * Reduced motion
 * ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .axe-select__content,
  .axe-select__content[data-state="closed"],
  .axe-switch__thumb,
  .axe-slider__input::-webkit-slider-thumb,
  .axe-slider__input::-moz-range-thumb,
  .axe-calendar__nav,
  .axe-calendar__day {
    animation: none;
    transition: none;
  }
}

/* source: styles/layout.css */
/* ============================================================
 * @axe/ui — Layout / Nav components (Phase 3)
 *
 * Owns: .axe-tabs__*, .axe-sidebar__*, .axe-breadcrumb__*, .axe-sheet__*
 * 토큰: --bg-*, --text-*, --border-*, --accent*, --space-*, --radius-*,
 *       --shadow-*, --duration-*, --ease-*, --font-* (모두 src/lib/tokens 정의).
 * 다크/라이트 자동 — CSS var 만 참조.
 * ============================================================ */

/* ============================================================
 *  Tabs — Radix Tabs 위 styling
 *
 *  horizontal: underline 활성 indicator + bottom border rail
 *  vertical:   좌측 indicator + 우측 컨텐츠
 * ============================================================ */
.axe-tabs {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.axe-tabs--vertical {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-6);
}

.axe-tabs__list {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: var(--space-1);
  border-bottom: 1px solid var(--border-subtle);
  /* Radix 가 자동으로 role="tablist" 부여, 키보드 nav 도 처리 */
}
.axe-tabs--vertical .axe-tabs__list {
  flex-direction: column;
  align-items: stretch;
  border-bottom: none;
  border-right: 1px solid var(--border-subtle);
  min-width: 12rem;
  padding-right: var(--space-2);
}

.axe-tabs__trigger {
  position: relative;
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-secondary);
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium, 500);
  line-height: 1.4;
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  white-space: nowrap;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-tabs__trigger:hover {
  color: var(--text-primary);
}
.axe-tabs__trigger:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.axe-tabs__trigger[data-state="active"] {
  color: var(--text-primary);
}
.axe-tabs__trigger[data-disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* horizontal indicator (bottom underline) */
.axe-tabs--horizontal .axe-tabs__trigger::after {
  content: "";
  position: absolute;
  left: var(--space-3);
  right: var(--space-3);
  bottom: -1px;
  height: 2px;
  background: var(--accent);
  border-radius: 2px 2px 0 0;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--duration-base) var(--ease-out);
}
.axe-tabs--horizontal .axe-tabs__trigger[data-state="active"]::after {
  transform: scaleX(1);
}

/* vertical indicator (left bar) */
.axe-tabs--vertical .axe-tabs__trigger {
  text-align: left;
  border-radius: var(--radius-sm);
}
.axe-tabs--vertical .axe-tabs__trigger::before {
  content: "";
  position: absolute;
  left: -1px;
  top: var(--space-2);
  bottom: var(--space-2);
  width: 2px;
  background: var(--accent);
  border-radius: 0 2px 2px 0;
  transform: scaleY(0);
  transform-origin: center;
  transition: transform var(--duration-base) var(--ease-out);
}
.axe-tabs--vertical .axe-tabs__trigger[data-state="active"]::before {
  transform: scaleY(1);
}
.axe-tabs--vertical .axe-tabs__trigger[data-state="active"] {
  background: var(--bg-subtle);
}

.axe-tabs__content {
  min-width: 0;
  flex: 1 1 auto;
}
.axe-tabs__content:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.axe-tabs__content[data-state="inactive"] {
  display: none;
}

/* ============================================================
 *  Sidebar — 자체 구현 (semantic <nav><ul><li>)
 *
 *  Group 은 collapsible 시 <button aria-expanded> + 패널 [hidden].
 *  활성 항목: aria-current="page" + .axe-sidebar__item--active.
 * ============================================================ */
.axe-sidebar {
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 14rem;
  padding: var(--space-3);
  background: var(--bg-base);
  color: var(--text-primary);
  border-right: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
}

.axe-sidebar__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.axe-sidebar__item {
  list-style: none;
}

/* 링크 — TOC(.axe-app-shell__toc-link) 와 같은 시각 언어 (2026-06-10 운영자
 * 피드백: 필 배경보다 레일+바가 좋다). 좌측 2px 보더가 group-list 의 1px
 * 레일에 -1px 로 겹치고, 활성이면 accent 바가 된다. 배경 필 없음. */
.axe-sidebar__link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  text-align: left;
  appearance: none;
  background: transparent;
  border: 0;
  border-left: 2px solid transparent;
  margin-left: -1px;
  color: var(--text-secondary);
  font: inherit;
  line-height: 1.4;
  padding: var(--space-1) var(--space-3);
  cursor: pointer;
  text-decoration: none;
  transition:
    color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}
.axe-sidebar__link:hover {
  color: var(--text-primary);
}
.axe-sidebar__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: var(--radius-sm);
}
.axe-sidebar__item--active > .axe-sidebar__link {
  color: var(--accent);
  border-left-color: var(--accent);
  font-weight: var(--weight-medium, 500);
}
.axe-sidebar__item--disabled > .axe-sidebar__link {
  opacity: 0.5;
  cursor: not-allowed;
}

.axe-sidebar__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
  color: var(--text-tertiary);
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-sidebar__item--active > .axe-sidebar__link .axe-sidebar__icon {
  color: var(--accent);
}

.axe-sidebar__label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Group */
.axe-sidebar__group {
  list-style: none;
  margin-top: var(--space-4);
}
.axe-sidebar__group:first-child {
  margin-top: 0;
}

/* 그룹 헤더 — TOC 타이틀과 같은 조용한 캡션. hover 는 색만 (배경 필 X). */
.axe-sidebar__group-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  text-align: left;
  appearance: none;
  background: transparent;
  border: 0;
  font: inherit;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: var(--weight-semibold, 600);
  color: var(--text-tertiary);
  padding: var(--space-2) var(--space-3) var(--space-1) 0;
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-sidebar__group-header:hover {
  color: var(--text-secondary);
}
.axe-sidebar__group-header--static {
  cursor: default;
}
.axe-sidebar__group-header--static:hover {
  color: var(--text-tertiary);
}
.axe-sidebar__group-header:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.axe-sidebar__group-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.axe-sidebar__chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
}

/* 그룹 패널 — TOC 리스트와 동일한 1px 레일. 링크의 -1px 2px 보더가 위에
 * 겹친다. 들여쓰기 없이 레일 자체가 계층을 표현. */
.axe-sidebar__group-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-left: 1px solid var(--border-subtle);
}
/* belt-and-braces — 위 display:flex 가 UA [hidden] 을 이기므로 컴포넌트
 * 스코프에서도 접기를 보장. reset.css 의 글로벌 [hidden] 가드는 별도
 * entry(./reset)라 components.css 단독 소비자에게는 안 깔린다 (어드버서리얼
 * 리뷰 2026-06-10). */
.axe-sidebar__group-list[hidden] {
  display: none;
}

/* ============================================================
 *  Breadcrumb
 * ============================================================ */
.axe-breadcrumb {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.axe-breadcrumb__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
}

.axe-breadcrumb__item {
  display: inline-flex;
  align-items: center;
  min-width: 0;
}

.axe-breadcrumb__link {
  color: var(--text-secondary);
  text-decoration: none;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-breadcrumb__link:hover {
  color: var(--text-primary);
  background: var(--bg-subtle);
}
.axe-breadcrumb__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.axe-breadcrumb__current {
  padding: var(--space-1) var(--space-2);
  color: var(--text-primary);
  font-weight: var(--weight-medium, 500);
  max-width: 24ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.axe-breadcrumb__separator {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: 1em;
  padding: 0 var(--space-1);
  user-select: none;
}

/* ============================================================
 *  Sheet (Drawer) — Radix Dialog 위 styling
 *
 *  side variant: left / right / top / bottom
 *  data-state="open|closed" → 슬라이드 in/out 애니메이션.
 * ============================================================ */
/* 불변식: overlay 층 > sticky chrome 층.
 *   --z-overlay(1000) > --z-sticky(100) 및 workspace rail 의 calc(--z-sticky + 1).
 * 종전의 raw 60/61 은 이 불변식을 깨서 Sheet 가 AppShell/workspace 의 sticky
 * topbar·rail 아래로 렌더됐다 (B-axe-ui-sheet-z-layer).
 *
 * overlay 와 content 는 *같은* --z-overlay 값을 쓴다 (+1 아님). 같은 밴드 안의
 * 순서는 portal DOM 순서가 정한다 — Radix 가 Overlay 를 Content 보다 먼저
 * portal 하므로 content 가 위에 그려지고, sheet 안에서 연 Popover·DropdownMenu
 * (역시 --z-overlay, 더 뒤에 portal) 도 계속 sheet 위에 뜬다. content 만 +1 로
 * 올리면 그 floating 표면들이 sheet 뒤로 숨는다.
 * AlertDialog 는 sheet 위를 덮어야 하므로 한 단 위 --z-modal (styles/menus.css). */
.axe-sheet__overlay {
  position: fixed;
  inset: 0;
  background: var(--bg-overlay);
  backdrop-filter: blur(2px);
  z-index: var(--z-overlay);
  animation: axe-sheet-overlay-in 180ms ease-out;
}
.axe-sheet__overlay[data-state="closed"] {
  animation: axe-sheet-overlay-out 140ms ease-in forwards;
}

/* Elevation tokens carry an inset rim in dark theme (--shadow-inset-rim) because
 * a floating card needs its own edge against the canvas. A sheet is not floating:
 * it is anchored to a viewport edge and its outer sides have no canvas to sit on.
 * The rim draws a 1px frame around all four of them — measured 2026-08-06 at
 * 375px as a closed box whose corners read as rounding, plus a 0-gap double line
 * where it met the panel's own border. Drawers take the drop shadow only. */
.axe-sheet__content {
  position: fixed;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  box-shadow: var(--shadow-drawer, 0 8px 16px rgb(0 0 0 / 0.28), 0 32px 80px -16px rgb(0 0 0 / 0.45));
  padding: var(--space-6);
  z-index: var(--z-overlay); /* 위 불변식 — overlay 와 동률, portal 순서로 위 */
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  overflow: auto;
}
.axe-sheet__content:focus { outline: none; }

/* right (default) */
.axe-sheet__content--right {
  top: 0;
  right: 0;
  bottom: 0;
  width: min(28rem, 92vw);
  max-width: 100vw;
  border-right: 0;
  border-top: 0;
  border-bottom: 0;
  /* Anchored drawers are square. A rounded inner edge reads as a floating card
   * that happens to touch the viewport, and it left the two drawer variants free
   * to differ per consumer — the operator saw a curve on a surface that does not
   * override this, while the docs site did. Corners belong to the contract. */
  border-radius: 0;
  animation: axe-sheet-in-right var(--duration-base) var(--ease-out);
}
.axe-sheet__content--right[data-state="closed"] {
  animation: axe-sheet-out-right var(--duration-fast) ease-in forwards;
}

/* left */
.axe-sheet__content--left {
  top: 0;
  left: 0;
  bottom: 0;
  width: min(20rem, 92vw);
  max-width: 100vw;
  border-left: 0;
  border-top: 0;
  border-bottom: 0;
  border-radius: 0;
  animation: axe-sheet-in-left var(--duration-base) var(--ease-out);
}
.axe-sheet__content--left[data-state="closed"] {
  animation: axe-sheet-out-left var(--duration-fast) ease-in forwards;
}

/* top */
.axe-sheet__content--top {
  top: 0;
  left: 0;
  right: 0;
  width: 100vw;
  max-height: min(80vh, 80dvh);
  border-top: 0;
  border-left: 0;
  border-right: 0;
  border-bottom-left-radius: var(--radius-xl);
  border-bottom-right-radius: var(--radius-xl);
  animation: axe-sheet-in-top var(--duration-base) var(--ease-out);
}
.axe-sheet__content--top[data-state="closed"] {
  animation: axe-sheet-out-top var(--duration-fast) ease-in forwards;
}

/* bottom */
.axe-sheet__content--bottom {
  bottom: 0;
  left: 0;
  right: 0;
  width: 100vw;
  max-height: min(80vh, 80dvh);
  border-bottom: 0;
  border-left: 0;
  border-right: 0;
  border-top-left-radius: var(--radius-xl);
  border-top-right-radius: var(--radius-xl);
  animation: axe-sheet-in-bottom var(--duration-base) var(--ease-out);
  /* safe-area for iOS PWA */
  padding-bottom: max(var(--space-6), env(safe-area-inset-bottom));
}
.axe-sheet__content--bottom[data-state="closed"] {
  animation: axe-sheet-out-bottom var(--duration-fast) ease-in forwards;
}

.axe-sheet__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-right: var(--space-8); /* close X 자리 */
}

.axe-sheet__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold, 600);
  font-size: var(--text-lg);
  line-height: 1.3;
  color: var(--text-primary);
  margin: 0;
}

.axe-sheet__description {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--text-secondary);
  margin: 0;
}

.axe-sheet__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}

/* keyframes — side 별 슬라이드 */
@keyframes axe-sheet-overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes axe-sheet-overlay-out {
  to { opacity: 0; }
}

@keyframes axe-sheet-in-right {
  from { transform: translate3d(100%, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes axe-sheet-out-right {
  to { transform: translate3d(100%, 0, 0); }
}
@keyframes axe-sheet-in-left {
  from { transform: translate3d(-100%, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes axe-sheet-out-left {
  to { transform: translate3d(-100%, 0, 0); }
}
@keyframes axe-sheet-in-top {
  from { transform: translate3d(0, -100%, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes axe-sheet-out-top {
  to { transform: translate3d(0, -100%, 0); }
}
@keyframes axe-sheet-in-bottom {
  from { transform: translate3d(0, 100%, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes axe-sheet-out-bottom {
  to { transform: translate3d(0, 100%, 0); }
}

/* ============================================================
 *  prefers-reduced-motion — 모든 transition/animation 비활성화
 * ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .axe-tabs__trigger,
  .axe-tabs--horizontal .axe-tabs__trigger::after,
  .axe-tabs--vertical .axe-tabs__trigger::before,
  .axe-sidebar__link,
  .axe-sidebar__group-header,
  .axe-sidebar__chevron svg,
  .axe-breadcrumb__link,
  .axe-sheet__overlay,
  .axe-sheet__content {
    transition: none !important;
    animation: none !important;
  }
}

/* ============================================================
 *  AppShell — 통합 layout chrome (Phase 15)
 *
 *  variant (data-shell attribute):
 *    docs       — TopNav + Sidebar + Content + TOC + Footer (3단)
 *    dashboard  — TopNav + Sidebar + Content + Footer (2단)
 *    landing    — TopNav + Content + Footer (단일단, hero-friendly)
 *
 *  CSS-only — React / Rust(maud) / Python(jinja) 모두 동일 markup 으로 사용 가능.
 *  React wrapper (src/lib/components/app-shell/) 는 슬롯 합성 + 행동만 추가.
 *
 *  CSS variables (override 가능):
 *    --app-shell-sidebar-w   (기본 240px)
 *    --app-shell-toc-w       (기본 220px)
 *    --app-shell-content-max (기본 80ch — docs / 1280px — dashboard / 100% — landing)
 *    --app-shell-gutter      (기본 var(--space-6))
 *    --app-shell-topbar-h    (기본 56px — .axe-topnav 와 동일. ≤767.98px 도 56px — v0.6 단일행 topnav)
 *    --app-shell-subnav-h    (기본 44px — ≤1023px subnav disclosure bar. anchor 보정용 공개 토큰)
 *
 *  HTML 표준 markup (React = maud = jinja 공통 — v0.5):
 *    <div class="axe-app-shell" data-shell="docs">
 *      <a href="#main" class="axe-skip-link">본문으로 건너뛰기</a>
 *
 *      <div class="axe-app-shell__topbar">
 *        <!-- ① TopNav — items 는 nav 직계 3-슬롯 (components.css 헤더 참조) -->
 *        <nav class="axe-topnav" aria-label="Main navigation">
 *          <div class="axe-topnav__left"><a class="axe-logo" href="/">AXE Labs</a></div>
 *          <div class="axe-topnav__items"><!-- data-fade = JS enhancement -->
 *            <a class="axe-topnav__item" aria-current="page" href="#principles">원칙</a>
 *            <a class="axe-topnav__item" href="#colors">Tokens</a>
 *          </div>
 *          <div class="axe-topnav__right"><!-- ThemeToggle 등 --></div>
 *        </nav>
 *
 *        <!-- ② subnav disclosure — topbar sticky wrapper *안* (top 오프셋
 *             var 동기화 불요). ≥1024px display:none. sidebar 있는 variant 만. -->
 *        <details class="axe-app-shell__subnav">
 *          <summary class="axe-app-shell__subnav-summary">
 *            <svg class="axe-app-shell__subnav-chevron" aria-hidden="true" width="12" height="12"
 *                 viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"
 *                 stroke-linecap="round" stroke-linejoin="round"><polyline points="9 6 15 12 9 18"/></svg>
 *            <span class="axe-app-shell__subnav-label">메뉴</span>
 *          </summary>
 *          <div class="axe-app-shell__subnav-panel">
 *            <nav class="axe-sidebar" aria-label="Primary"><!-- 데스크톱 column 과 동일 markup --></nav>
 *            <div class="axe-app-shell__subnav-toc"><!-- docs variant + toc 있을 때만 --></div>
 *          </div>
 *        </details>
 *      </div>
 *
 *      <div class="axe-app-shell__main">
 *        <aside class="axe-app-shell__sidebar" aria-label="Primary">…</aside>
 *        <main id="main" class="axe-app-shell__content">…</main>
 *        <aside class="axe-app-shell__toc" aria-label="On this page">…</aside>
 *      </div>
 *      <div class="axe-app-shell__footer"><footer class="axe-footer">…</footer></div>
 *    </div>
 * ============================================================ */
:root {
  --app-shell-sidebar-w: 240px;
  --app-shell-toc-w: 220px;
  --app-shell-gutter: var(--space-6);
  --app-shell-topbar-h: 56px;
  /* 공개 토큰 — 커스텀 anchor 보정용 (≤1023px subnav bar 높이) */
  --app-shell-subnav-h: 44px;
}

.axe-app-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--bg-base);
  color: var(--text-primary);
}

/* topbar slot — .axe-topnav 가 자체 sticky/blur. slot 은 stacking 만. */
.axe-app-shell__topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky, 100);
}

/* main — sidebar / content / toc 의 grid 컨테이너 */
.axe-app-shell__main {
  flex: 1 1 auto;
  display: grid;
  width: 100%;
  min-width: 0;
  grid-template-columns: minmax(0, 1fr); /* default (landing) = single column */
}

/* CSS-only backward-compatible defaults: markup without React-emitted presence
 * attributes keeps the documented docs=3-column/dashboard=2-column contract. */
.axe-app-shell[data-shell="docs"] .axe-app-shell__main {
  grid-template-columns: var(--app-shell-sidebar-w) minmax(0, 1fr) var(--app-shell-toc-w);
}
.axe-app-shell[data-shell="dashboard"] .axe-app-shell__main {
  grid-template-columns: var(--app-shell-sidebar-w) minmax(0, 1fr);
}

/* React can explicitly collapse absent slots without changing CSS-only markup. */
.axe-app-shell[data-shell="docs"][data-has-sidebar="true"][data-has-toc="false"] .axe-app-shell__main,
.axe-app-shell[data-shell="dashboard"][data-has-sidebar="true"] .axe-app-shell__main {
  grid-template-columns: var(--app-shell-sidebar-w) minmax(0, 1fr);
}
.axe-app-shell[data-shell="docs"][data-has-sidebar="false"][data-has-toc="true"] .axe-app-shell__main {
  grid-template-columns: minmax(0, 1fr) var(--app-shell-toc-w);
}
.axe-app-shell[data-shell="docs"][data-has-sidebar="false"][data-has-toc="false"] .axe-app-shell__main,
.axe-app-shell[data-shell="dashboard"][data-has-sidebar="false"] .axe-app-shell__main {
  grid-template-columns: minmax(0, 1fr);
}

/* sidebar slot — .axe-sidebar 가 내부 styling, slot 은 sticky/scroll 만. */
.axe-app-shell__sidebar {
  grid-column: 1;
  position: sticky;
  top: var(--app-shell-topbar-h);
  align-self: start;
  max-height: calc(100vh - var(--app-shell-topbar-h));
  max-height: calc(100dvh - var(--app-shell-topbar-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--bg-base);
  border-right: 1px solid var(--border-subtle);
}

/* content slot — variant 별 max-width / padding */
.axe-app-shell__content {
  min-width: 0;
  padding: var(--app-shell-gutter);
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.axe-app-shell[data-shell="docs"] .axe-app-shell__content {
  max-width: var(--app-shell-content-max, 80ch);
  margin-inline: auto;
  width: 100%;
}
.axe-app-shell[data-shell="dashboard"] .axe-app-shell__content {
  max-width: var(--app-shell-content-max, 1280px);
  width: 100%;
  margin-inline: auto;
}
.axe-app-shell[data-shell="landing"] .axe-app-shell__content {
  /* full width — Hero/Section composites 가 자체 max-width 결정 */
  padding: 0;
  gap: 0;
}

/* TOC slot */
.axe-app-shell__toc {
  grid-column: 3;
  position: sticky;
  top: var(--app-shell-topbar-h);
  align-self: start;
  max-height: calc(100vh - var(--app-shell-topbar-h));
  max-height: calc(100dvh - var(--app-shell-topbar-h));
  overflow-y: auto;
  padding: var(--space-5) var(--space-4);
  border-left: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
  background: var(--bg-base);
}
.axe-app-shell[data-shell="docs"][data-has-sidebar="false"][data-has-toc="true"] .axe-app-shell__toc {
  grid-column: 2;
}
.axe-app-shell__toc-title {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-tertiary);
  margin-bottom: var(--space-3);
  font-weight: var(--weight-semibold, 600);
}
.axe-app-shell__toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-left: 1px solid var(--border-subtle);
}
.axe-app-shell__toc-link {
  position: relative;
  display: block;
  color: var(--text-secondary);
  text-decoration: none;
  padding: var(--space-1) var(--space-3);
  margin-left: -1px;
  border-left: 2px solid transparent;
  font-size: var(--text-sm);
  line-height: 1.4;
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-app-shell__toc-link:hover {
  color: var(--text-primary);
}
.axe-app-shell__toc-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: var(--radius-sm);
}
.axe-app-shell__toc-link[aria-current="location"] {
  color: var(--accent);
  border-left-color: var(--accent);
  font-weight: var(--weight-medium, 500);
}
.axe-app-shell__toc-link--h3 {
  padding-left: calc(var(--space-3) + var(--space-3));
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}

/* footer slot — .axe-footer 가 내부 styling. slot 은 spacing 만. */
.axe-app-shell__footer {
  padding: 0 var(--app-shell-gutter);
}
.axe-app-shell[data-shell="landing"] .axe-app-shell__footer {
  background: var(--bg-subtle);
  border-top: 1px solid var(--border-subtle);
}

/* tablet & mobile (≤1023px) — 3-column 무너뜨림, sidebar/toc 숨김.
 * sidebar 내용은 아래 subnav disclosure 로 이동, toc 는 subnav 패널 하단.
 *
 * 첫 두 selector 는 presence-attribute 없는 CSS-only markup 용 (0,3,0) — 위
 * `[data-shell="docs"]`(0,3,0) / `[data-shell="dashboard"]`(0,3,0) base 를
 * source order 로 이긴다.
 *
 * 나머지 3개는 React 가 내보내는 presence-attribute 조합을 *그대로 반복*한다.
 * 그 base 규칙들은 (0,5,0)·(0,5,0)·(0,4,0) 이라 (0,3,0) 규칙을 눌러버렸고,
 * 그 결과 슬롯 하나가 접힌 2-zone 페이지는 모바일에서 sidebar/toc 가
 * display:none 이 된 뒤에도 그 트랙(240·220·280px)이 살아남아, grid-column 을
 * 명시하지 않는 .axe-app-shell__content 가 그 죽은 칼럼으로 auto-place 됐다
 * (cortex 2-zone 채택에서 발견 — data-has-toc="false" 조합, D-ui-9 phase-3).
 * specificity 를 올리는 대신 base 와 *동일한* selector 를 여기서 반복해
 * 동점을 만들고 source order 로 이긴다 — 소비자가 (0,6,0) 로 덮어쓰는
 * arms race 를 만들지 않는 게 요점.
 *
 * 3-zone(docs + sidebar=true + toc=true)은 아래 어느 selector 와도 매칭되지
 * 않는다 — 셋 다 toc="false" 또는 sidebar="false" 또는 shell="dashboard" 를
 * 요구한다. 게다가 선언값은 이미 (0,3,0) 규칙이 3-zone 에 적용하던 것과
 * 동일한 minmax(0, 1fr) 이라 기하 변화가 원리적으로 불가능하다. */
@media (max-width: 1023.98px) {
  .axe-app-shell[data-shell="docs"] .axe-app-shell__main,
  .axe-app-shell[data-shell="dashboard"] .axe-app-shell__main,
  .axe-app-shell[data-shell="docs"][data-has-sidebar="true"][data-has-toc="false"] .axe-app-shell__main,
  .axe-app-shell[data-shell="docs"][data-has-sidebar="false"][data-has-toc="true"] .axe-app-shell__main,
  .axe-app-shell[data-shell="dashboard"][data-has-sidebar="true"] .axe-app-shell__main {
    grid-template-columns: minmax(0, 1fr);
  }
  .axe-app-shell__sidebar,
  .axe-app-shell__toc {
    display: none;
  }
}

/* ============================================================
 *  AppShell subnav — ≤1023px sticky disclosure (v0.5)
 *
 *  데스크톱 sidebar column 이 접히는 폭에서 같은 네비를 topbar 안의
 *  <details> bar 로 노출. topbar sticky wrapper *안* 에 중첩이라
 *  top 오프셋 var 동기화 문제 자체가 없음. 비모달 disclosure —
 *  scrim/focus trap/scroll lock 의도적 부재 (WAI-ARIA 패턴 준수).
 * ============================================================ */
.axe-app-shell__subnav {
  display: none;                   /* 데스크톱 부재 — [open] 잔존해도 무해 */
}

@media (max-width: 1023.98px) {
  .axe-app-shell__subnav {
    display: block;
    /* 패널 absolute 의 containing block — topbar sticky 직접 의존 대신
     * details 자체에 relative (iOS Safari sticky 모서리 회피) */
    position: relative;
    /* blur 비사용 — topnav 와 2중 backdrop-filter 비용 회피
     * (components.css 의 blur 커널 축소 결정과 정합) */
    background: var(--bg-base);
    border-bottom: 1px solid var(--border-subtle);
  }
  .axe-app-shell__subnav-summary {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--app-shell-subnav-h);
    padding: 0 var(--space-4);
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium, 500);
    color: var(--text-secondary);
    cursor: pointer;
    user-select: none;
    list-style: none;
  }
  .axe-app-shell__subnav-summary::-webkit-details-marker {
    display: none;
  }
  .axe-app-shell__subnav-summary:hover {
    color: var(--text-primary);
  }
  .axe-app-shell__subnav-summary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
  }
  .axe-app-shell__subnav[open] .axe-app-shell__subnav-summary {
    color: var(--text-primary);
  }
  .axe-app-shell__subnav-chevron {
    display: inline-flex;
    color: var(--text-muted);
    /* Sidebar Chevron(right→90°) 과 동일 언어 */
    transition: transform var(--duration-fast) var(--ease-out);
  }
  .axe-app-shell__subnav[open] .axe-app-shell__subnav-chevron {
    transform: rotate(90deg);
  }

  /* 패널 — absolute overlay: 본문 layout shift 0 (in-flow push 거부 — CLS) */
  .axe-app-shell__subnav-panel {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    max-height: calc(100dvh - var(--app-shell-topbar-h) - var(--app-shell-subnav-h));
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    background: var(--bg-base);
    border-bottom: 1px solid var(--border-subtle);
    box-shadow: var(--shadow-lg);
    padding: var(--space-2) var(--space-2) var(--space-5);
  }
  .axe-app-shell__subnav-panel .axe-sidebar {
    border-right: 0;
    min-width: 0;
  }
  .axe-app-shell__subnav-toc {
    margin-top: var(--space-4);
    padding: var(--space-4) var(--space-3) 0;
    border-top: 1px solid var(--border-subtle);
  }

  /* anchor 착지 보정 — 범용 [id]. 근사 generous 값: 작아서 가리는 것만 금지
   * (과보정은 착지가 약간 내려올 뿐 가림 없음). */
  .axe-app-shell {
    --app-shell-topbar-h: 56px;
  }
  .axe-app-shell__content [id] {
    scroll-margin-top: calc(var(--app-shell-topbar-h) + var(--app-shell-subnav-h, 0px) + var(--space-3));
  }
}

/* small mobile — content gutter 축소 */
@media (max-width: 767.98px) {
  .axe-app-shell {
    --app-shell-gutter: var(--space-4);
    /* v0.6 (2026-06-17): 모바일 topnav = 단일 행 56px (종전 2행 92px 폐지,
     * components.css). 드로어가 인라인 items/right 를 대체하므로 topbar 높이
     * 계약은 56px 단일행. */
    --app-shell-topbar-h: 56px;
  }
}

/* 인쇄 — chrome 전부 숨김 + single column. .axe-doc(document.css) 경로와 무교차. */
@media print {
  .axe-app-shell__topbar,
  .axe-app-shell__subnav,
  .axe-app-shell__sidebar,
  .axe-app-shell__toc,
  .axe-app-shell__footer,
  .axe-skip-link {
    display: none !important;
  }
  .axe-app-shell[data-shell] .axe-app-shell__main {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* prefers-reduced-motion — AppShell transition 비활성화 */
@media (prefers-reduced-motion: reduce) {
  .axe-app-shell__toc-link,
  .axe-app-shell__subnav-chevron {
    transition: none !important;
  }
}

/* ============================================================
 *  Layout primitives — Stack / Cluster / Grid / Container (Phase 16)
 *
 *  CSS-only.  React wrapper (src/lib/components/layout/) 는 prop → class
 *  매핑만 한다.  matrix / cortex 처럼 inline col()/grid()/max-width 를
 *  재발명하던 비-Tailwind 소비자가 동일 markup 으로 채택 가능
 *  (Tailwind 0 원칙 — SSOT 가 spacing/layout utility 를 직접 제공).
 *
 *    Stack     — 세로 flex + gap            (구 col())
 *    Cluster   — 가로 flex + wrap + gap      (toolbar / inline row / header)
 *    Grid      — 반응형 grid                 (구 grid(N)) — cols 1~6 또는 auto-fill
 *    Container — max-width 중앙 정렬 + gutter (구 <main style={{maxWidth}}>)
 *
 *  gap modifier 는 spacing scale (--space-N) 0~8 단계와 1:1 (default 는
 *  Stack/ Grid = --space-4, Cluster = --space-3).
 * ============================================================ */

/* --- Stack (vertical) --- */
.axe-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}
.axe-stack--gap-0 { gap: 0; }
.axe-stack--gap-1 { gap: var(--space-1); }
.axe-stack--gap-2 { gap: var(--space-2); }
.axe-stack--gap-3 { gap: var(--space-3); }
.axe-stack--gap-4 { gap: var(--space-4); }
.axe-stack--gap-5 { gap: var(--space-5); }
.axe-stack--gap-6 { gap: var(--space-6); }
.axe-stack--gap-7 { gap: var(--space-7); }
.axe-stack--gap-8 { gap: var(--space-8); }
.axe-stack--gap-9 { gap: var(--space-9); }
.axe-stack--gap-10 { gap: var(--space-10); }
.axe-stack--align-start { align-items: flex-start; }
.axe-stack--align-center { align-items: center; }
.axe-stack--align-end { align-items: flex-end; }
.axe-stack--align-stretch { align-items: stretch; }

/* --- Cluster (horizontal, wraps) --- */
.axe-cluster {
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}
.axe-cluster--gap-0 { gap: 0; }
.axe-cluster--gap-1 { gap: var(--space-1); }
.axe-cluster--gap-2 { gap: var(--space-2); }
.axe-cluster--gap-3 { gap: var(--space-3); }
.axe-cluster--gap-4 { gap: var(--space-4); }
.axe-cluster--gap-5 { gap: var(--space-5); }
.axe-cluster--gap-6 { gap: var(--space-6); }
.axe-cluster--gap-7 { gap: var(--space-7); }
.axe-cluster--gap-8 { gap: var(--space-8); }
.axe-cluster--gap-9 { gap: var(--space-9); }
.axe-cluster--gap-10 { gap: var(--space-10); }
.axe-cluster--nowrap { flex-wrap: nowrap; }
.axe-cluster--align-start { align-items: flex-start; }
.axe-cluster--align-center { align-items: center; }
.axe-cluster--align-end { align-items: flex-end; }
.axe-cluster--align-baseline { align-items: baseline; }
.axe-cluster--align-stretch { align-items: stretch; }
.axe-cluster--justify-start { justify-content: flex-start; }
.axe-cluster--justify-center { justify-content: center; }
.axe-cluster--justify-end { justify-content: flex-end; }
.axe-cluster--justify-between { justify-content: space-between; }

/* --- Grid --- */
.axe-grid {
  display: grid;
  gap: var(--space-4);
  min-width: 0;
}
.axe-grid--gap-0 { gap: 0; }
.axe-grid--gap-1 { gap: var(--space-1); }
.axe-grid--gap-2 { gap: var(--space-2); }
.axe-grid--gap-3 { gap: var(--space-3); }
.axe-grid--gap-4 { gap: var(--space-4); }
.axe-grid--gap-5 { gap: var(--space-5); }
.axe-grid--gap-6 { gap: var(--space-6); }
.axe-grid--cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.axe-grid--cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.axe-grid--cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.axe-grid--cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.axe-grid--cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.axe-grid--cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
/* auto-fill: 카드가 --axe-grid-min 폭 이하로 줄지 않게 자동 wrap (cortex .cortex-metric-grid 대체) */
.axe-grid--auto {
  grid-template-columns: repeat(auto-fill, minmax(var(--axe-grid-min, 15rem), 1fr));
}

/* responsive — cols-N 을 작은 화면에서 단계적으로 접음.
   inline var 가 아니라 modifier class 라 media query 가 specificity 로 override 가능. */
@media (max-width: 1023.98px) {
  .axe-grid--responsive.axe-grid--cols-3,
  .axe-grid--responsive.axe-grid--cols-4,
  .axe-grid--responsive.axe-grid--cols-5,
  .axe-grid--responsive.axe-grid--cols-6 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 639.98px) {
  .axe-grid--responsive.axe-grid--cols-2,
  .axe-grid--responsive.axe-grid--cols-3,
  .axe-grid--responsive.axe-grid--cols-4,
  .axe-grid--responsive.axe-grid--cols-5,
  .axe-grid--responsive.axe-grid--cols-6 {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* --- Container (max-width centered + gutter) --- */
.axe-container {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--space-4);
  max-width: var(--axe-container-max, 72rem);
}
.axe-container--sm { --axe-container-max: 40rem; }
.axe-container--md { --axe-container-max: 56rem; }
.axe-container--lg { --axe-container-max: 72rem; }
.axe-container--xl { --axe-container-max: 80rem; }
.axe-container--full { --axe-container-max: 100%; }

/* ============================================================
 *  ThemeToggle — light / system / dark control (Phase 16)
 *
 *  useTheme 위 thin control.  segment(3-버튼) / cycle(단일 순환) 두 형태.
 *  matrix·blueprint·design 페이지가 각자 재발명하던 토글을 SSOT 로 흡수.
 *  내부 버튼은 .axe-btn 재사용 — 별도 색 정의 없음 (segment wrap 만 정의).
 * ============================================================ */
.axe-theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.axe-theme-toggle__icon {
  display: inline-flex;
  width: 1em;
  height: 1em;
  flex: 0 0 auto;
}
.axe-theme-toggle__icon svg {
  width: 100%;
  height: 100%;
}

/* source: styles/workspace-shell.css */
/* ============================================================
 * @axe/ui — Workspace shell
 *
 * Stable, framework-neutral application chrome shared by Design and Gate.
 * Use these classes together with AppShell's semantic slot markup:
 *
 * .axe-app-shell.axe-workspace-shell[data-shell="docs"]
 *   > .axe-app-shell__topbar > .axe-workspace-bar
 *   > .axe-app-shell__main
 *       > .axe-app-shell__sidebar > .axe-workspace-rail
 *       > .axe-app-shell__content
 *       > .axe-app-shell__toc > .axe-workspace-context
 *
 * Editorial composition stays with each route. This file owns only chrome,
 * neutral materials, rail rhythm, and responsive geometry.
 *
 * Content canvas knobs (override 가능 — layout.css 의 --app-shell-* 관례와 동일):
 *   --workspace-content-max   작업면 최대 폭        (기본 68rem)
 *   --workspace-content-pad   작업면 세로 여백      (기본 clamp(2.5rem, 5vw, 5.5rem))
 *
 * 가로 여백은 별도 knob 이 없다 — .axe-app-shell__content 의 padding-inline 은
 * 이미 --app-shell-gutter 로 노출돼 있어 중복 노출할 이유가 없다.
 *
 * --workspace-content-pad 는 .axe-workspace-shell 블록에 선언하지 *않고* 소비처의
 * var() fallback 으로만 기본값을 준다. 블록에 선언하면 그 값이 :root 나 상위
 * 컨테이너의 선언을 이겨버려, 가장 자연스러운 override 지점이 조용히 무시된다.
 * fallback 형태면 :root · 상위 래퍼 · 셸 루트 · __content 어디서 설정해도 먹는다
 * (blueprint /axe/projects/[id] IDE 처럼 height:calc(100svh - 56px) 패널을 쓰는
 * 전체높이 표면이 세로 여백을 0 으로 접기 위해 필요 — D-ui-9 후속).
 * ============================================================ */

/* 재료 선언은 셸 root 와 *portal 로 셸 밖에 렌더되는 표면* 이 공유한다.
 * React 소비자의 entity 메뉴는 popper portal 이라 body 직속에 붙는다 — 셸 변수를
 * 상속받지 못하므로 같은 선언을 자기 자신에도 실어야 native <details> 안에 남는
 * 패널과 같은 재료가 된다. 셸 변수를 소비처에서 override 하는 소비자는 portal
 * 표면에도 같은 override 를 실어야 한다(portal 의 본질적 성질).
 *
 * identity 메뉴 패널·서브패널도 같은 이유로 여기에 든다 — native <details> 안에서는
 * 셸이 이미 준 값을 같은 값으로 다시 선언할 뿐이고(무해), Radix 처럼 portal 로 띄우는
 * 소비자에게는 이 선언이 유일한 재료 공급원이다. */
.axe-workspace-shell,
.axe-workspace-entity__menu,
.axe-workspace-identity-menu__panel,
.axe-workspace-identity-menu__submenu,
.axe-workspace-picker-dialog {
  --workspace-canvas: var(--gray-1);
  --workspace-rail: var(--gray-3);
  --workspace-surface: light-dark(#ffffff, var(--gray-4));
  --workspace-selected: light-dark(#e4e4e2, #393939);
  --workspace-border: var(--gray-7);
  --workspace-border-strong: var(--gray-8);
  --workspace-text: var(--gray-12);
  --workspace-muted: light-dark(#666663, #a7a7a7);
  --workspace-wine: var(--brand-claret);
  --workspace-green: var(--palette-green);
  --workspace-blue: var(--palette-blue);
  --workspace-blue-fg: var(--accent-fg);
  --workspace-orange: var(--palette-orange);
  --workspace-overlay: light-dark(rgb(0 0 0 / 0.38), rgb(0 0 0 / 0.68));
  --workspace-rail-w: 280px;
  /* 우측 컨텍스트 레일은 좌측 primary rail 의 1.5배(420px)다. 두 레일은 폭을
   * 나눠 쓰던 시절이 있었지만 같은 값이어야 할 이유가 없었다 — 좌측은 라벨
   * 한 줄짜리 목적지 목록이고, 우측은 문단·프롬프트 카드·채팅 도크가 사는
   * 읽기면이다. 280px 에서 그 내용은 톱니처럼 접혔다(운영자 지시 2026-08-10).
   *
   * 좌측 폭에서 파생시키는 것은 두 레일이 같아야 해서가 아니라 셸의 세로줄이
   * 한 리듬에서 나오게 하기 위함이다 — rail 을 바꾸면 context 도 따라 움직인다. */
  --workspace-context-w: calc(var(--workspace-rail-w) * 1.5);
  /* rail 에서 열리는 메뉴(entity 전환 · identity)의 공통 폭 — rail 폭에서 좌우
   * 4px 씩 물러난 272px. 좁은 뷰포트에서는 화면을 넘지 않도록 잘린다. */
  --workspace-menu-w: min(
    calc(var(--workspace-rail-w) - var(--space-2)),
    calc(100vw - 24px)
  );
  --workspace-content-max: 68rem;
  --workspace-topbar-h: 56px;
  --workspace-nav-row-h: 30px;
  --workspace-nav-row-gap: 1px;

  --app-shell-sidebar-w: var(--workspace-rail-w);
  --app-shell-toc-w: var(--workspace-context-w);
  --app-shell-content-max: var(--workspace-content-max);
  --app-shell-gutter: clamp(1.25rem, 2.5vw, 3rem);
  --app-shell-topbar-h: var(--workspace-topbar-h);
  --bg-base: var(--workspace-canvas);
  --bg-subtle: var(--workspace-selected);
  --bg-elevated: var(--workspace-surface);
  --bg-overlay: var(--workspace-overlay);
  --text-primary: var(--workspace-text);
  --text-secondary: var(--workspace-muted);
  --text-tertiary: var(--workspace-muted);
  --text-muted: var(--workspace-muted);
  --border-subtle: var(--workspace-border);
  --border-default: var(--workspace-border-strong);
  --border-strong: var(--workspace-border-strong);
  --accent-hover: var(--workspace-text);
  --accent-soft: color-mix(in srgb, var(--workspace-blue) 12%, transparent);
}

.axe-workspace-shell {
  background: var(--workspace-canvas);
  color: var(--workspace-text);
}

/* 넓은 작업면 — opt-in modifier. 표와 콘솔처럼 밀도가 목적인 표면은 캔버스 캡을
 * 풀어 남는 폭을 그대로 쓴다. 캡을 푸는 것과 여백을 없애는 것은 다른 결정이라
 * 거터(--app-shell-gutter)는 그대로 남는다 — full-bleed 가 필요한 소비자는
 * 거터를 0 으로 두는 별도 선언을 한다(blueprint 선례). */
.axe-workspace-shell--wide {
  --workspace-content-max: none;
}

.axe-workspace-shell :is(.axe-app-shell__sidebar, .axe-app-shell__toc) {
  min-width: 0;
  height: calc(100vh - var(--workspace-topbar-h));
  height: calc(100dvh - var(--workspace-topbar-h));
  box-sizing: border-box;
  overflow-x: hidden;
  background: var(--workspace-rail);
  border-color: var(--workspace-border);
}

.axe-workspace-shell .axe-app-shell__content {
  width: 100%;
  max-width: var(--workspace-content-max);
  gap: 0;
  /* fallback = 종전 하드코딩 값 그대로 → 미설정 소비자는 픽셀 무변화. */
  padding-block: var(--workspace-content-pad, clamp(2.5rem, 5vw, 5.5rem));
  /* Clip the inline axis only. `overflow: clip` on both axes made this a non-scrollable
     clipping box: the grid row sized it to ~5.5k px while its content ran to ~9k, so
     everything past the fold was cut off with no way to scroll to it — the 결재 처리 card's
     승인/반려/보류 buttons were unreachable. `clip`/`visible` is a legal pair (unlike
     hidden/auto, which force the other axis to `auto`), so the block axis stays in the
     page's normal scroll flow. */
  overflow-x: clip;
  overflow-y: visible;
  background: var(--workspace-canvas);
}

/* Doc stages embedded in the workspace shell must not re-derive their height
   from the stretched grid row. `.axe-doc-stage { min-height: 100% }` is a
   showcase/viewer default: inside the shell it creates a percentage cycle —
   the auto grid row is measured with the percentage resolving to auto, then
   final layout resolves 100% against the stretched content box, inflating the
   stage past the row and pushing every following sibling out of the shell
   (the 결재 처리 card became unreachable, 2026-08-02/03). Standalone viewer
   surfaces (sign/member task shell) keep the backdrop-fill default. */
.axe-workspace-shell .axe-app-shell__content .axe-doc-stage {
  min-height: auto;
}

.axe-workspace-shell .axe-app-shell__toc {
  padding: 0;
}

/*
 * Full-viewport page patterns become center-canvas compositions when embedded
 * in the workspace shell. The rails already carry product context, so repeating
 * a second desktop split inside the bounded canvas would squeeze or clip the
 * landing and authentication surfaces around the 1024–1440px breakpoints.
 */
.axe-workspace-shell .axe-pattern-landing,
.axe-workspace-shell .axe-pattern-auth {
  min-height: calc(100vh - var(--workspace-topbar-h));
  min-height: calc(100dvh - var(--workspace-topbar-h));
}

.axe-workspace-shell .axe-pattern-landing__hero {
  min-height: auto;
  grid-template-columns: minmax(0, 1fr);
}

.axe-workspace-shell .axe-pattern-auth {
  display: block;
}

.axe-workspace-shell .axe-pattern-auth__context {
  display: none;
}

.axe-workspace-shell .axe-pattern-auth__stage {
  min-height: calc(100vh - var(--workspace-topbar-h));
  min-height: calc(100dvh - var(--workspace-topbar-h));
  padding: clamp(var(--space-6), 5vw, var(--space-10));
}

/* Workspace bar ------------------------------------------------------- */

.axe-workspace-bar {
  min-height: var(--workspace-topbar-h, 56px);
  display: grid;
  grid-template-columns: 108px minmax(0, 1fr) minmax(108px, max-content);
  align-items: center;
  background: var(--workspace-canvas);
  border-bottom: 1px solid var(--workspace-border);
}

.axe-workspace-bar__left,
.axe-workspace-bar__center,
.axe-workspace-bar__right {
  min-width: 0;
  height: 100%;
  display: flex;
  align-items: center;
  padding-inline: var(--space-2);
}

.axe-workspace-bar__center {
  justify-content: center;
}

.axe-workspace-bar__right {
  justify-content: flex-end;
  gap: var(--space-1);
}

.axe-workspace-bar__mobile-brand {
  min-width: 0;
  display: flex;
  align-items: center;
}

/* 0.25.1 — rail 이 접힌 폭에서 이 워드마크가 rail brand 행을 대신한다. 그러므로
 * .axe-workspace-entity 의 워드마크와 같은 글자여야 한다: sans · text-lg · bold ·
 * −0.01em · 본문색. 종전(text-base · medium · wine)은 같은 제품 이름이 데스크톱과
 * 모바일에서 다른 글자로 보이게 했고, 소비자가 `.axe-logo` 를 넣으면 brand 식자
 * (Clash)까지 섞여 들어왔다 — font-family 를 여기서 확정해 그 경로를 닫는다. */
.axe-workspace-bar__mobile-brand > :is(a, span) {
  min-width: 0;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  overflow: hidden;
  color: var(--workspace-text);
  font-family: var(--font-sans);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.axe-workspace-bar__icon-button,
.axe-workspace-disclosure > summary {
  width: 44px;
  height: 44px;
  display: inline-flex;
  flex: 0 0 44px;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--workspace-muted);
  list-style: none;
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}

/* 레일 접기 토글 — 표식 하나, 자리는 둘. 기본은 감춤이고 상태에 맞는 인스턴스만
 * ≥1024px 에서 되살아난다(아래 geometry 절). 접힌 레일에는 토글을 얹을 면이 없어
 * 펼침용 토글은 레일 brand 행에, 접힘용 토글은 bar 좌측 칸에 산다. 치수·재료는
 * 각자의 자리가 준다 — bar 인스턴스는 .axe-workspace-bar__icon-button 과 함께,
 * 레일 인스턴스는 brand 행의 28px 리듬(아래 규칙)으로. */
.axe-workspace-rail-toggle {
  display: none;
}

.axe-workspace-disclosure {
  position: static;
}

.axe-workspace-disclosure > summary::-webkit-details-marker {
  display: none;
}

.axe-workspace-disclosure[open] > summary {
  color: var(--workspace-text);
  background: var(--workspace-selected);
  border-color: var(--workspace-border);
}

.axe-workspace-disclosure__panel {
  position: fixed;
  z-index: calc(var(--z-overlay, 400) + 1);
  top: var(--workspace-topbar-h);
  bottom: 0;
  width: min(calc(100vw - 40px), var(--workspace-rail-w));
  overflow: hidden auto;
  overscroll-behavior: contain;
  background: var(--workspace-rail);
  border-color: var(--workspace-border);
  box-shadow: var(--shadow-xl);
}

.axe-workspace-disclosure--navigation .axe-workspace-disclosure__panel {
  left: 0;
  border-right: 1px solid var(--workspace-border);
}

/* 서랍은 <1440px 의 컨텍스트 레일 **그 자체**다(≥1440 에서는 이 disclosure 가
 * 숨고 toc 사본이 선다). 같은 패널이 폭만 달라지면 같은 내용이 두 조판으로
 * 읽히므로, 서랍도 context 폭을 쓴다 — `min()` 의 뷰포트 항이 좁은 화면을
 * 계속 지켜 준다(390px 폰에서 350px). */
.axe-workspace-disclosure--context .axe-workspace-disclosure__panel {
  right: 0;
  width: min(calc(100vw - 40px), var(--workspace-context-w));
  border-left: 1px solid var(--workspace-border);
}

.axe-workspace-disclosure__panel > :is(.axe-workspace-rail, .axe-workspace-context) {
  min-height: 100%;
}

/* disclosure 패널은 바로 아래에 있는 바가 이미 브랜드를 들고 있다 — 한 화면에 같은
 * 이름을 두 번 그리지 않는다. identity 행은 기본값(보임)을 그대로 쓴다. */
.axe-workspace-disclosure__panel .axe-workspace-rail__brand {
  display: none;
}

.axe-workspace-bar__routes {
  width: min(100%, var(--workspace-content-max));
  height: 100%;
  display: none;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding-inline: var(--app-shell-gutter);
}

.axe-workspace-bar__routes a {
  min-height: 36px;
  display: inline-flex;
  align-items: center;
  padding-inline: var(--space-3);
  border-radius: var(--radius-md);
  color: var(--workspace-muted);
  font-size: var(--text-sm);
  text-decoration: none;
  white-space: nowrap;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}

.axe-workspace-bar__routes a[aria-current="page"] {
  color: var(--workspace-text);
  background: var(--workspace-selected);
  font-weight: var(--weight-regular);
}

/* Primary rail -------------------------------------------------------- */

.axe-workspace-rail {
  min-width: 0;
  height: 100%;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: var(--workspace-text);
}

/* 0.25.1 — brand·identity 행의 기본값은 **보임**이다.
 * 종전 기본값은 `display: none` 이었고 ≥1024px 의 `.axe-app-shell__sidebar` 안에서만
 * 되살아났다. 그런데 <1024px 에서 sidebar 슬롯 자체가 이미 display:none 이므로
 * (layout.css) 그 감춤은 데스크톱 레일에는 아무 일도 하지 않았고, 대신 **모바일 시트·
 * 패널로 레일을 옮겨 그리는 소비자에게만** 작동했다 — 정확히 서비스 전환기와
 * entity/계정 칩이 모바일에서 닿을 수 없게 만드는 자리다. 그래서 각 소비자가 자기
 * 로컬 CSS 로 이 감춤을 되돌리고 있었다(design 사이트의 `.axe-design-sheet--nav` 규칙).
 * 기본을 보임으로 바꾸고, 감출 이유가 있는 표면만 감춘다
 * (`.axe-workspace-disclosure__panel` = 바가 이미 브랜드를 들고 있는 경우). */
.axe-workspace-rail__brand {
  min-width: 0;
  display: flex;
  flex: 0 0 var(--workspace-topbar-h);
  align-items: center;
  gap: var(--space-1);
  padding-inline: var(--space-2);
  background: var(--workspace-rail);
}

/*
 * Entity switcher — rail brand 행의 "현재 조직/제품" 칩과 그 전환 메뉴.
 *
 * 한 칩이 세 렌더러에서 같은 모양이 되도록 trigger 를 두 shape 로 받는다:
 *   native   <details class="axe-workspace-entity"><summary>…</summary><div>…</div></details>
 *   trigger  <button class="axe-workspace-entity" aria-expanded="true">…</button>
 *            + portal <div class="axe-workspace-entity__menu">…</div>
 * 전환할 entity 가 애초에 없는 단일-도메인 소비자를 위한 네 번째 shape 가 `--static` 이다:
 *   static   <span class="axe-workspace-entity axe-workspace-entity--static">…</span>
 * 같은 칩 스킨을 받되 조작을 약속하지 않는다(chevron·hover/open·cursor 없음). 열 것이
 * 없는데 chevron 을 그리면 그 자체가 거짓 affordance 라, 이건 축약이 아니라 정확성이다.
 *
 * 열림 상태는 프레임워크 신호를 **병렬로** 받는다 — `[open]`(native details) ·
 * `[aria-expanded="true"]`(ARIA) · `[data-state="open"]`(Radix). context tab 계약이
 * `[aria-current]/[aria-selected]/[data-state]` 를 병렬로 받는 것과 같은 패턴이다.
 *
 * chevron 은 trigger 의 svg 자식이 있으면 그것을 회전시키고, 없으면(markup-only
 * 소비자) 같은 자리에 CSS 글리프를 그린다. 두 경로가 동시에 그려지지 않는다.
 *
 * 패널 selector 는 `details.axe-workspace-entity > :not(summary)` 로 **요소 한정**이다.
 * trigger 자신이 칩인 shape 에서는 라벨·chevron 이 곧 `> :not(summary)` 라, 한정 없이는
 * 자식 두 개가 패널로 그려진다(실측 확인). details 가 아닌 shape 는 패널에
 * `.axe-workspace-entity__menu` 를 명시한다.
 */

.axe-workspace-entity {
  position: relative;
  min-width: 0;
  flex: 1 1 auto;
}

/* The rail wordmark carries the product name, so it is set in the display size
 * and bold rather than tinted — colour is spent on state, not on the name. Same
 * 28px chip and 8px radius as the identity chip at the other end of the rail,
 * so the two ends of the column agree. */
.axe-workspace-entity:is(a, button),
.axe-workspace-entity > summary,
.axe-workspace-entity--static {
  min-width: 0;
  min-height: 28px;
  display: flex;
  align-items: center;
  gap: 6px;
  padding-inline: var(--space-2);
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--workspace-text);
  font: inherit;
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  letter-spacing: -0.01em;
  list-style: none;
  text-align: left;
  text-decoration: none;
}

/* 조작 affordance 는 인터랙티브 갈래만 갖는다 — `--static` 은 같은 칩 스킨을 받되
 * cursor·전환·chevron·hover/open 상태를 전부 얻지 않는다. */
.axe-workspace-entity:is(a, button),
.axe-workspace-entity > summary {
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}

.axe-workspace-entity > summary::-webkit-details-marker {
  display: none;
}

.axe-workspace-entity__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 14px — 라벨(--text-lg/bold) 옆에서 방향만 알리는 크기. svg 자체 width/height
 * 속성에 맡기면 소비자마다 칩의 chevron 이 달라지므로 계약이 못 박는다. */
.axe-workspace-entity:is(a, button) > svg,
.axe-workspace-entity > summary > svg {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  color: var(--workspace-muted);
  transition: transform var(--duration-fast) var(--ease-out);
}

.axe-workspace-entity:is(a, button):not(:has(> svg))::after,
.axe-workspace-entity > summary:not(:has(> svg))::after {
  width: 6px;
  height: 6px;
  flex: 0 0 auto;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  color: var(--workspace-muted);
  content: "";
  transform: translateY(-1px) rotate(45deg);
  transition: transform var(--duration-fast) var(--ease-out);
}

.axe-workspace-entity[open] > summary,
.axe-workspace-entity:is(a, button):is([aria-expanded="true"], [data-state="open"]) {
  color: var(--workspace-text);
  background: var(--workspace-selected);
}

.axe-workspace-entity[open] > summary > svg,
.axe-workspace-entity:is(a, button):is([aria-expanded="true"], [data-state="open"]) > svg {
  transform: rotate(180deg);
}

.axe-workspace-entity[open] > summary::after,
.axe-workspace-entity:is(a, button):is([aria-expanded="true"], [data-state="open"])::after {
  transform: translateY(2px) rotate(225deg);
}

.axe-workspace-entity:is(a, button):focus-visible,
.axe-workspace-entity > summary:focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: -2px;
}

/* 메뉴 표면 — in-flow(<details> 자식)든 portal 이든 같은 재료·같은 치수.
 *
 * 클래스를 두 번 쓰는 건 오타가 아니다: components.css 는 menus.css 를 이 파일
 * *뒤에* import 하므로, 같은 (0,1,0) 인 `.axe-dropdown-menu__content` 가 나중
 * 규칙으로 이긴다. entity 메뉴는 그 generic 메뉴 표면 위에 얹는 workspace 스킨이라
 * 한 단계를 명시적으로 올린다 (실측: 이게 없으면 radius 14→6px · padding 8→4px ·
 * 전용 그림자 → --shadow-lg 로 조용히 되돌아간다). `details …` 갈래는 이미
 * (0,1,2) 라 추가 조치가 필요 없다. */
.axe-workspace-entity__menu.axe-workspace-entity__menu,
details.axe-workspace-entity > :not(summary) {
  width: var(--workspace-menu-w);
  min-width: var(--workspace-menu-w);
  padding: var(--space-1);
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--workspace-border-strong);
  border-radius: 12px;
  background: var(--workspace-surface);
  color: var(--workspace-text);
  font-family: var(--font-sans);
  box-shadow:
    0 2px 6px color-mix(in srgb, var(--workspace-overlay) 32%, transparent),
    0 18px 44px -14px color-mix(in srgb, var(--workspace-overlay) 72%, transparent);
}

.axe-workspace-entity__menu.axe-workspace-entity__menu {
  z-index: calc(var(--z-overlay, 1000) + 2);
  /* Radix 가 재는 가용 높이. 다른 popper 런타임에서는 미정의 → max-height 무효
   * (initial `none`) 이므로 이 줄이 non-Radix 소비자를 좁히지 않는다. */
  max-height: var(--radix-dropdown-menu-content-available-height);
}

/* in-flow 패널만 자기 위치를 소유한다. portal 패널의 위치는 host popper 가 잡는다. */
details.axe-workspace-entity > :not(summary) {
  position: absolute;
  z-index: var(--z-popover, 300);
  top: calc(100% + 6px);
  left: 0;
  max-height: calc(100dvh - var(--workspace-topbar-h, 56px) - 24px);
}

details.axe-workspace-entity > :not(summary) .axe-workspace-rail__link {
  min-height: 40px;
}

/* 한 줄 옵션 행 — entity 메뉴 표면(in-flow · portal 공통). */
.axe-workspace-entity__menu > :is(a, button),
details.axe-workspace-entity > :not(summary) > :is(a, button) {
  width: 100%;
  min-height: 40px;
  display: flex;
  align-items: center;
  padding-inline: var(--space-2);
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--workspace-muted);
  font: inherit;
  font-size: var(--text-sm);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

/* 두 줄 옵션 행 — 6 + 20 + 2 + 18 + 6 = 52px. 열 개짜리 서비스 목록이 벽이 아니라
 * 목록으로 읽히는 최소 여유다(Radix 소비자는 같은 치수를 __item 갈래에서 받는다).
 *
 * 이 갈래는 `__row` 를 품은 행에만 걸리므로 자기 상자를 통째로 갖는다 — identity
 * 패널처럼 `.axe-workspace-rail__link` 행이 이미 사는 표면에서도, 두 줄 행만 이
 * 기하를 받고 옆의 한 줄 링크는 건드리지 않는다. */
:is(
  .axe-workspace-entity__menu,
  .axe-workspace-identity-menu__panel,
  details.axe-workspace-entity > :not(summary)
) > :is(a, button):has(> .axe-workspace-entity__row) {
  width: 100%;
  min-height: 52px;
  display: flex;
  align-items: center;
  padding: 6px var(--space-2);
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--workspace-muted);
  font: inherit;
  font-size: var(--text-sm);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.axe-workspace-entity__menu > :is(a, button):hover,
details.axe-workspace-entity > :not(summary) > :is(a, button):hover,
:is(
  .axe-workspace-entity__menu,
  .axe-workspace-identity-menu__panel,
  details.axe-workspace-entity > :not(summary)
) > :is(a, button):has(> .axe-workspace-entity__row):hover {
  color: var(--workspace-text);
  background: var(--workspace-selected);
}

.axe-workspace-entity__menu > :is(a, button):focus-visible,
details.axe-workspace-entity > :not(summary) > :is(a, button):focus-visible,
:is(
  .axe-workspace-entity__menu,
  .axe-workspace-identity-menu__panel,
  details.axe-workspace-entity > :not(summary)
) > :is(a, button):has(> .axe-workspace-entity__row):focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: -2px;
}

/* 메뉴 옵션 행 — 이름/설명 + 우측 슬롯(짧은 식별자 또는 현재 항목 체크).
 * Radix 소비자의 행은 `.axe-dropdown-menu__item-label` 이 같은 자리에 오므로 같은
 * 규칙을 받는다 — 한 markup 계약이 두 renderer 에서 같은 격자가 된다. */
.axe-workspace-entity__row,
.axe-workspace-entity__menu .axe-dropdown-menu__item-label {
  width: 100%;
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
  overflow: visible;
}

/* 20px + 2px + 18px = 40px. 행 상하 6px 을 더해 52px 이 된다. */
.axe-workspace-entity__copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.axe-workspace-entity__copy strong {
  overflow: hidden;
  color: var(--workspace-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 20px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.axe-workspace-entity__copy small {
  overflow: hidden;
  color: var(--workspace-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-regular);
  line-height: 18px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 설정 행의 현재값 — 라벨은 왼쪽, 값은 오른쪽 끝. 회색인 것은 이 값이 **요약**이기
 * 때문이다: 고르는 일은 이 행이 여는 픽커가 하고, 여기서는 지금 무엇인지만 말한다. */
.axe-workspace-entity__value {
  min-width: 0;
  overflow: hidden;
  flex: 0 1 auto;
  margin-left: auto;
  color: var(--workspace-muted);
  font-size: var(--text-sm);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Radix 갈래에서는 값이 `.axe-dropdown-menu__item-label` 안에 산다 — 그 상자는
 * block 이라 margin-left:auto 가 듣지 않는다. 값을 가진 행에서만 flex 로 바꾼다. */
:is(.axe-workspace-identity-menu__panel, .axe-workspace-entity__menu)
  .axe-dropdown-menu__item-label:has(> .axe-workspace-entity__value) {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.axe-workspace-entity__meta {
  flex: 0 0 auto;
  color: var(--workspace-muted);
  font-family: var(--font-mono);
  font-size: 0.65rem;
  text-transform: uppercase;
}

/* 현재 항목 표시 — 행 오른쪽 슬롯(두 번째 grid 열)에 놓인 체크 글리프. 전용
 * 클래스가 아니라 자리로 정의한다: 두 renderer 의 markup 이 이미 이 자리를
 * 공유하므로, 클래스를 하나 더 만들면 계약만 늘고 결과는 같다. 색은 라벨과 같아
 * "선택됨" 을 색이 아니라 존재 여부로 말한다. */
.axe-workspace-entity__row > svg,
.axe-workspace-entity__menu .axe-dropdown-menu__item-label > svg {
  width: 16px;
  height: 16px;
  color: var(--workspace-text);
}

/* DropdownMenu 를 메뉴 본문으로 쓰는 소비자용 bridge. `.axe-dropdown-menu__*` 는
 * `styles/menus.css`(full 프로파일) 소유라 core-data 소비자에겐 무해하게 비활성이다.
 * 선택 표시는 `[data-state="checked"]`(Radix)와 `[aria-checked="true"]`(ARIA)를 병렬로 받는다. */
.axe-workspace-entity__menu .axe-dropdown-menu__label {
  padding: var(--space-1) var(--space-2) var(--space-2);
  color: var(--workspace-muted);
  font-family: var(--font-sans);
  font-weight: var(--weight-regular);
  letter-spacing: 0;
  text-transform: none;
}

.axe-workspace-entity__menu .axe-dropdown-menu__item {
  min-height: 52px;
  gap: var(--space-2);
  padding: 6px var(--space-2);
  border-radius: 6px;
}

.axe-workspace-entity__menu .axe-dropdown-menu__item-indicator {
  order: 2;
  margin-left: auto;
  color: var(--workspace-text);
}

.axe-workspace-entity__menu .axe-dropdown-menu__item-indicator svg {
  display: none;
}

.axe-workspace-entity__menu .axe-dropdown-menu__item-indicator::before {
  width: 8px;
  height: 4px;
  display: none;
  border-bottom: 1.5px solid currentColor;
  border-left: 1.5px solid currentColor;
  content: "";
  transform: rotate(-45deg) translateY(-1px);
}

.axe-workspace-entity__menu
  .axe-dropdown-menu__item:is([data-state="checked"], [aria-checked="true"])
  .axe-dropdown-menu__item-indicator::before {
  display: block;
}

.axe-workspace-rail__body {
  min-width: 0;
  min-height: 0;
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}

/* Footer row is sized from the chip it holds: 1px rule + 8 + 28 + 8 = 45px.
 * `--stacked` is the two-row form — entity over account — which reads as one
 * sentence: which organisation, then who I am inside it. It stays opt-in
 * because a service without an entity axis (layer) has only the account chip
 * and a column of one is just the single row with extra padding. */
.axe-workspace-rail__identity {
  min-width: 0;
  display: flex;
  flex: 0 0 45px;
  align-items: center;
  gap: var(--space-1);
  padding-inline: var(--space-2);
  border-top: 1px solid var(--workspace-border);
  background: var(--workspace-rail);
}

.axe-workspace-rail__identity--stacked {
  flex: 0 0 77px;
  flex-direction: column;
  align-items: stretch;
  padding-block: var(--space-2);
}

.axe-workspace-identity {
  min-width: 0;
  min-height: 28px;
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: var(--space-2);
  padding-inline: var(--space-2);
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--workspace-text);
  font: inherit;
  font-size: var(--text-sm);
  text-align: left;
  text-decoration: none;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}

.axe-workspace-identity:is(a, button, summary) {
  cursor: pointer;
}

.axe-workspace-identity:focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: -2px;
}

/* 열림 상태는 entity 칩과 같은 세 신호를 병렬로 받는다 — `[open]`(native details,
 * 부모에 붙는다) · `[aria-expanded]` · `[data-state]`. */
.axe-workspace-identity:is([aria-expanded="true"], [data-state="open"]),
details[open] > .axe-workspace-identity {
  background: var(--workspace-selected);
}

/* entity 행 칩 — 계정 칩과 같은 28px 상자에 선행 18px 마크를 얹는다.
 * 라벨은 regular weight: 이 행은 "어느 조직인가" 라는 사실이지 강조가 아니다.
 *
 * 0.30.0 부터 chevron 은 선택이다(운영자 확정: entity 칩에서 제거). 그래서 후행
 * chevron 규칙은 `:not(:first-child)` 로 자기 자리를 못 박는다 — 마크 하나만 남으면
 * 그 svg 가 `:first-child` 이자 `:last-child` 라, 가드가 없으면 18px 조직 마크가
 * 14px 로 줄고 180° 돌아간다(실측). */
.axe-workspace-identity--entity > svg:first-child {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  color: var(--workspace-muted);
}

.axe-workspace-identity--entity > svg:last-child:not(:first-child) {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  color: var(--workspace-muted);
  /* 메뉴가 위로 열리므로, 쉬는 chevron 은 열릴 방향을 가리킨다. */
  transform: rotate(180deg);
  transition: transform var(--duration-fast) var(--ease-out);
}

.axe-workspace-identity--entity:is([aria-expanded="true"], [data-state="open"])
  > svg:last-child:not(:first-child),
details[open] > .axe-workspace-identity--entity > svg:last-child:not(:first-child) {
  transform: none;
}

.axe-workspace-identity__avatar {
  width: 18px;
  height: 18px;
  display: inline-flex;
  flex: 0 0 18px;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--workspace-wine);
  color: var(--text-inverse);
  font-size: 0.64rem;
  line-height: 1;
}

.axe-workspace-identity__label {
  min-width: 0;
  overflow: hidden;
  flex: 1 1 auto;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The wordmark owns the left of the brand row; search is pushed to its end. */
.axe-workspace-rail__brand > .axe-workspace-search {
  margin-left: auto;
}

/* 펼침 상태의 접기 토글은 레일 자신의 머리에 앉는다 — bar 좌측 칸은 데스크톱에서
 * 레일(sticky, topbar 보다 위 z-index)에 덮여 있어 그 자리의 버튼은 보이지도
 * 눌리지도 않는다. brand 행의 28px 아이콘 리듬(검색)을 그대로 쓰고,
 * 검색의 margin-left:auto 뒤에 놓여 행의 오른쪽 끝을 검색과 나눠 갖는다. */
.axe-workspace-rail__brand .axe-workspace-rail-toggle {
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--workspace-muted);
  font: inherit;
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}

.axe-workspace-rail__brand .axe-workspace-rail-toggle:focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: -2px;
}

@media (hover: hover) and (pointer: fine) {
  .axe-workspace-rail__brand .axe-workspace-rail-toggle:hover {
    color: var(--workspace-text);
    background: var(--workspace-selected);
    border-color: transparent;
  }
}

@media (hover: hover) and (pointer: fine) {
  .axe-workspace-search[data-icon-only="true"]:hover {
    color: var(--workspace-text);
    background: var(--workspace-selected);
    border-color: transparent;
  }
}

/* The tight desktop chrome is a pointer-precision affordance; touch still gets
 * 44px targets, and the rows grow with them. */
@media (pointer: coarse) {
  .axe-workspace-rail__identity {
    flex-basis: 61px;
  }

  .axe-workspace-rail__identity--stacked {
    flex-basis: 109px;
  }

  .axe-workspace-identity,
  .axe-workspace-entity:is(a, button),
  .axe-workspace-entity > summary {
    min-height: 44px;
  }

  /* rail 에서 열리는 메뉴의 행도 같이 자란다 — 승격 전에는 각 서비스가 이 복원을
   * 로컬 CSS 로 다시 썼다. 계약이 실제 크롬 셀렉터를 덮지 못하면 그렇게 된다. */
  .axe-workspace-entity__menu > :is(a, button),
  details.axe-workspace-entity > :not(summary) > :is(a, button),
  .axe-workspace-identity-menu__panel > :is(a, button):has(> .axe-workspace-entity__row),
  .axe-workspace-entity__menu .axe-dropdown-menu__item,
  .axe-workspace-identity-menu__panel .axe-dropdown-menu__item,
  .axe-workspace-identity-menu__submenu .axe-dropdown-menu__item,
  .axe-workspace-identity-menu__panel .axe-workspace-rail__link {
    height: auto;
    min-height: 44px;
  }

  .axe-workspace-search[data-icon-only="true"] {
    width: 44px;
    min-width: 44px;
    min-height: 44px;
  }
}

.axe-workspace-identity-menu {
  position: relative;
  min-width: 0;
  flex: 1 1 auto;
}

.axe-workspace-identity-menu > summary {
  width: 100%;
  list-style: none;
}

.axe-workspace-identity-menu > summary::-webkit-details-marker {
  display: none;
}

.axe-workspace-identity-menu > summary::after {
  width: 6px;
  height: 6px;
  flex: 0 0 auto;
  border-top: 1.5px solid currentColor;
  border-left: 1.5px solid currentColor;
  content: "";
  transform: translateY(2px) rotate(45deg);
  transition: transform var(--duration-fast) var(--ease-out);
}

.axe-workspace-identity-menu[open] > summary {
  background: var(--workspace-selected);
}

.axe-workspace-identity-menu[open] > summary::after {
  transform: translateY(-1px) rotate(225deg);
}

/* identity 메뉴 표면 — entity 메뉴와 같은 분업이다: 재료·치수는 두 shape 가 공유하고,
 * 위치는 in-flow 패널만 소유한다(portal 패널의 위치는 host popper 가 잡는다).
 *
 * 클래스를 두 번 쓰는 이유도 같다 — `menus.css` 가 이 파일 뒤에 import 되므로 같은
 * (0,1,0) 인 `.axe-dropdown-menu__content` 가 이긴다. Radix DropdownMenuContent 에
 * 이 클래스를 얹는 소비자를 위해 한 단계 올린다. */
.axe-workspace-identity-menu__panel.axe-workspace-identity-menu__panel,
.axe-workspace-identity-menu__submenu.axe-workspace-identity-menu__submenu {
  z-index: calc(var(--z-overlay, 1000) + 2);
  padding: var(--space-1);
  border: 1px solid var(--workspace-border-strong);
  border-radius: 12px;
  background: var(--workspace-surface);
  color: var(--workspace-text);
  font-family: var(--font-sans);
  box-shadow:
    0 2px 6px color-mix(in srgb, var(--workspace-overlay) 32%, transparent),
    0 18px 44px -14px color-mix(in srgb, var(--workspace-overlay) 72%, transparent);
}

.axe-workspace-identity-menu__panel.axe-workspace-identity-menu__panel {
  width: var(--workspace-menu-w);
  min-width: var(--workspace-menu-w);
}

/* 서브패널은 자기 내용만큼만 — 언어·표시처럼 짧은 라디오 목록이 rail 폭을 흉내 낼
 * 이유가 없다. */
.axe-workspace-identity-menu__submenu.axe-workspace-identity-menu__submenu {
  min-width: 168px;
}

details.axe-workspace-identity-menu > .axe-workspace-identity-menu__panel {
  position: absolute;
  z-index: var(--z-popover, 300);
  bottom: calc(100% + 8px);
  left: 0;
  transform-origin: left bottom;
  animation: axe-workspace-identity-menu-in 160ms var(--ease-out);
}

@keyframes axe-workspace-identity-menu-in {
  from {
    opacity: 0;
    transform: translateY(3px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.axe-workspace-identity-menu__panel > :is(a, form, .axe-workspace-identity) {
  width: 100%;
}

.axe-workspace-identity-menu__panel .axe-workspace-rail__link {
  width: 100%;
}

/* identity 메뉴 리듬 — 한 박자로 유지한다: 4px 패널 패딩 · 22px 라벨 · 24px 행 ·
 * 1px 구분선(위아래 4px). 라벨 텍스트·행 텍스트·구분선의 가로 끝이 모두 같은 12px
 * 안쪽선(4px 패널 + 8px 행 패딩)에 앉는 것이, 이 열을 "세 개의 비슷한 왼쪽 여백"이
 * 아니라 하나의 왼쪽 여백으로 읽히게 한다.
 *
 * `.axe-dropdown-menu__*` base 는 `styles/menus.css`(full 프로파일) 소유라
 * core-data 소비자에게는 무해하게 비활성이다. */
.axe-workspace-identity-menu__panel .axe-dropdown-menu__label,
.axe-workspace-identity-menu__submenu .axe-dropdown-menu__label {
  min-height: 22px;
  display: flex;
  align-items: center;
  padding: 0 var(--space-2);
  color: var(--workspace-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  letter-spacing: normal;
  text-transform: none;
}

.axe-workspace-identity-menu__panel .axe-dropdown-menu__separator,
.axe-workspace-identity-menu__submenu .axe-dropdown-menu__separator {
  margin: var(--space-1) var(--space-2);
  background: var(--workspace-border);
}

.axe-workspace-identity-menu__panel .axe-dropdown-menu__item,
.axe-workspace-identity-menu__submenu .axe-dropdown-menu__item {
  min-height: 24px;
  padding-block: 0;
  padding-inline: var(--space-2);
  border-radius: 6px;
  font-size: var(--text-sm);
}

/* 글리프와 라벨이 한 행을 공유해, 아이콘 있는 항목과 라디오 항목의 텍스트가 같은
 * 36px 열(12 안쪽선 + 16 글리프 + 8 간격)에서 시작한다. */
.axe-workspace-identity-menu__panel .axe-dropdown-menu__item-label,
.axe-workspace-identity-menu__submenu .axe-dropdown-menu__item-label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  overflow: visible;
}

.axe-workspace-identity-menu__panel .axe-dropdown-menu__item-label > svg,
.axe-workspace-identity-menu__submenu .axe-dropdown-menu__item-label > svg {
  flex: 0 0 16px;
  color: var(--workspace-muted);
}

.axe-workspace-identity-menu__panel .axe-dropdown-menu__sub-chevron,
.axe-workspace-identity-menu__submenu .axe-dropdown-menu__sub-chevron {
  color: var(--workspace-muted);
}

.axe-workspace-rail__nav {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--workspace-nav-row-gap);
  margin: 0;
  padding: var(--space-2) var(--space-2) var(--space-6);
  border: 0;
  background: transparent;
}

.axe-workspace-rail__nav:is(.axe-sidebar) {
  --design-nav-row-h: var(--workspace-nav-row-h);
  --design-nav-row-gap: var(--workspace-nav-row-gap);
}

.axe-workspace-rail__nav :is(.axe-sidebar__list, .axe-sidebar__group-list) {
  gap: var(--workspace-nav-row-gap);
}

.axe-workspace-rail__nav .axe-sidebar__group {
  margin-top: 0;
}

.axe-workspace-rail__nav .axe-sidebar__group-list {
  margin-top: var(--workspace-nav-row-gap);
  padding-left: 0;
  border-left: 0;
}

.axe-workspace-rail__group-label,
.axe-workspace-rail__link,
.axe-workspace-rail__nav :is(.axe-sidebar__group-header, .axe-sidebar__link) {
  min-height: var(--workspace-nav-row-h);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 3px var(--space-2);
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--workspace-muted);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  line-height: 1.35;
  letter-spacing: 0;
  text-align: left;
  text-decoration: none;
  text-transform: none;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}

.axe-workspace-rail__group-label:is(a, button),
.axe-workspace-rail__link:is(a, button),
.axe-workspace-rail__nav :is(.axe-sidebar__group-header, .axe-sidebar__link) {
  cursor: pointer;
}

/* 그룹 라벨은 링크가 아니다 — 같은 30px 행·같은 muted 안에서 **굵기 하나**로
 * 갈린다(500 대 400). 위 블록이 라벨과 링크에 같은 400 을 주면 대메뉴 캡션과
 * 그 아래 목적지가 한 덩어리로 읽히고, 그 순간 소비자는 로컬 CSS 로 캡션을
 * 다시 칠한다(그것이 킷 어휘가 서비스마다 갈라지는 첫 걸음이다). 값은 새로
 * 정하는 것이 아니라 `.axe-sidebar__group-header` 가 이 레일에서 이미 서 있는
 * 값(14.4px · 500 · --workspace-muted)이다 — 두 이름이 같은 규칙을 공유한다. */
.axe-workspace-rail__group-label,
.axe-workspace-rail__nav .axe-sidebar__group-header {
  font-weight: var(--weight-medium);
}

.axe-workspace-rail__nav .axe-sidebar__group-list .axe-sidebar__link,
.axe-workspace-rail__link[data-level="2"] {
  padding-left: var(--space-6);
}

.axe-workspace-rail__link[aria-current="page"],
.axe-workspace-rail__nav .axe-sidebar__item--active > .axe-sidebar__link {
  color: var(--workspace-text);
  background: var(--workspace-selected);
  font-weight: var(--weight-regular);
}

.axe-workspace-rail__group-label:focus-visible,
.axe-workspace-rail__link:focus-visible,
.axe-workspace-rail__nav :is(.axe-sidebar__group-header, .axe-sidebar__link):focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: -2px;
}

/* Search -------------------------------------------------------------- */

/* rail brand 행과 top bar 우측 어느 쪽에 놓여도 같은 검색 affordance 가 된다 —
 * 40px 슬롯을 채우는 elevated 칩. 배치는 부모 track 의 gap 이 결정하므로 별도
 * 배치 클래스가 없다. `data-icon-only` 는 아이콘 외 자식(라벨·단축키)을 감춘다. */
.axe-workspace-search {
  min-width: 40px;
  min-height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0 var(--space-2) 0 var(--space-3);
  border: 1px solid var(--workspace-border-strong);
  border-radius: var(--radius-md);
  background: var(--workspace-surface);
  color: var(--workspace-muted);
  font: inherit;
  font-size: var(--text-sm);
  box-shadow: var(--shadow-xs);
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}

/* Icon-only search is a glyph affordance, not a field: it drops the border,
 * surface, and shadow that make the text variant read as an input. Keyed to the
 * variant rather than to a location, because the same control renders in the
 * rail brand row and in the top bar and "borderless" was never a fact about
 * where it sat. */
.axe-workspace-search[data-icon-only="true"] {
  width: 28px;
  min-width: 28px;
  min-height: 28px;
  padding: 0;
  border-color: transparent;
  border-radius: 8px;
  background: transparent;
  box-shadow: none;
}

.axe-workspace-search[data-icon-only="true"] > svg {
  width: 16px;
  height: 16px;
}

.axe-workspace-search[data-icon-only="true"] > :not(svg) {
  display: none;
}

.axe-workspace-search:focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: 2px;
}

dialog.axe-workspace-search-dialog.axe-cmdk-backdrop {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding-inline: var(--space-4);
  border: 0;
  color: var(--workspace-text);
}

dialog.axe-workspace-search-dialog:not([open]) {
  display: none;
}

dialog.axe-workspace-search-dialog::backdrop {
  background: transparent;
}

/* Drawer context ------------------------------------------------------ */

/* 0.27.0 — rail 을 서랍 안으로 옮기면 그 부품들이 상자가 된다.
 *
 * rail 은 본문 **옆에 서는 기둥**으로 설계돼 있다. 그래서 부품마다 자기 배경과
 * 자기 테두리를 갖는다 — brand 행은 rail 색을 칠하고, identity 행은 위에 선을
 * 긋고, 그 사이 소비자가 끼우는 목록도 자기 위아래에 선을 긋는다. 기둥에서는 그게
 * 하나의 면으로 읽힌다: 바깥에 본문이 있으니 각 부품의 선은 *기둥 안의 리듬*이다.
 *
 * 같은 rail 을 서랍(모바일 시트·drawer)에 넣으면 전제가 뒤집힌다. 서랍이 이미
 * 하나의 면이므로 부품의 선과 칠은 면 안의 **상자**가 되고, 상자가 5개 쌓인다
 * (운영자 2026-08-06 375px 보고: 헤더 · brand · route 목록 · 트리 · identity).
 *
 * 그래서 서랍 안에서는:
 *   1. rail 의 직계 부품은 배경도 테두리도 갖지 않는다 — 면은 서랍의 것 하나뿐이다.
 *      `> *` 인 이유는 소비자가 brand 행 아래 끼우는 목록(route 목록 등)도 같은
 *      자리의 부품이기 때문이다. 계약이 그 이름을 알 필요는 없고, 알아야 하는 것은
 *      "rail 의 직계 자식은 상자가 아니다" 뿐이다.
 *   2. 이음매는 **한 번만** 그어진다. 아래쪽 형제가 자기 border-top 으로 긋고,
 *      위쪽 형제는 border-bottom 을 갖지 않는다 — 두 이웃이 각자 그으면 2px 이
 *      되고, 그것이 "두 줄" 로 보이던 원인이다.
 *   3. 이음매는 **기능이 바뀌는 곳**에만 있다. 서랍에서 고정된 것은 맨 아래
 *      identity 행 하나이고, 그 위 brand·목록·트리는 함께 스크롤하는 한 덩어리의
 *      탐색이다. 그 안을 다시 가르면 상자로 되돌아간다.
 *
 * `.axe-sheet__content` 를 함께 받는 이유는 이 계약이 이미 출하하는 서랍이 React
 * Sheet 이기 때문이다 — 소비자가 아무것도 붙이지 않아도 맞는 화면이 나와야 한다.
 * `.axe-workspace-drawer` 는 서랍을 직접 짓는 maud·jinja 소비자를 위한 표식이다.
 * 두 선택자 모두 rail 부품에만 내려가므로, rail 없는 시트에는 아무 영향이 없다. */
:is(.axe-workspace-drawer, .axe-sheet__content) .axe-workspace-rail > * {
  border: 0;
  background: transparent;
}

:is(.axe-workspace-drawer, .axe-sheet__content)
  :is(.axe-workspace-rail__brand, .axe-workspace-rail__body, .axe-workspace-rail__identity) {
  border: 0;
  background: transparent;
}

/* 유일한 이음매 — 스크롤하는 탐색과 고정된 identity 사이. 위 reset 과 같은
 * 명시도(0,2,0)라 순서로 이긴다: reset 다음에 와야 한다. */
:is(.axe-workspace-drawer, .axe-sheet__content) .axe-workspace-rail__identity {
  border-top: 1px solid var(--workspace-border);
}

/* Picker dialog ------------------------------------------------------- */

/* 0.26.0 — rail 의 세 전환기(서비스 · entity · 계정)는 데스크톱에서 rail 에 붙어
 * 열리는 드롭다운이다. 바가 접히는 폭에서는 붙을 rail 이 없다: 트리거가 시트나 바
 * 안에 있어, 드롭다운은 이미 스크롤 중인 표면 안에서 다시 스크롤되는 작은 목록이
 * 된다. 그래서 접힌 폭에서는 같은 행들을 **검색과 같은 팝업**으로 띄운다 —
 * `.axe-workspace-search-dialog` 가 이미 쓰는 native `<dialog>` 형태를 그대로 이어,
 * JS 프레임워크 없는 소비자도 `dialog.showModal()` 하나로 같은 동작을 만든다.
 * Esc·backdrop 클릭·닫기 버튼이 모두 닫는다(앞의 둘은 native, 마지막은 `close()`).
 *
 * markup (계약):
 *   <dialog class="axe-workspace-picker-dialog" aria-label="서비스 전환">
 *     <div class="axe-workspace-picker">
 *       <div class="axe-workspace-picker__header">
 *         <strong>서비스</strong>
 *         <button class="axe-workspace-picker__close" aria-label="닫기">…</button>
 *       </div>
 *       <div class="axe-workspace-picker__list">
 *         <p class="axe-workspace-picker__label">Language</p>
 *         <button class="axe-workspace-picker__item" aria-current="true">
 *           <span class="axe-workspace-entity__copy"><strong>…</strong><small>…</small></span>
 *           <svg …/>            <!-- 현재 항목 체크 -->
 *         </button>
 *       </div>
 *     </div>
 *   </dialog>
 *
 * 행은 두 줄이든 한 줄이든 44px 아래로 내려가지 않는다 — 이 표면은 터치에서만
 * 열리므로 최소 치수가 곧 기본 치수다. `<dialog>` 는 top layer 라 셸 변수를
 * 상속받지 못한다: 위 재료 선언 블록에 자기 셀렉터를 실어 둔 이유다. */
.axe-workspace-picker-dialog {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: var(--space-4);
  display: flex;
  /* 엄지에 가까운 아래쪽에 붙는다. 넓은 화면에서는 아래 미디어쿼리가 가운데로. */
  align-items: flex-end;
  justify-content: center;
  border: 0;
  background: transparent;
  color: var(--workspace-text);
  overscroll-behavior: contain;
}

.axe-workspace-picker-dialog:not([open]) {
  display: none;
}

/* ::backdrop 은 최신 브라우저에서 originating element 의 상속을 받지만, 그렇지
 * 않은 곳에서도 같은 scrim 이 서도록 fallback 을 함께 적는다. */
.axe-workspace-picker-dialog::backdrop {
  background: var(--workspace-overlay, rgb(0 0 0 / 0.5));
}

.axe-workspace-picker {
  width: min(420px, 100%);
  max-height: min(70dvh, 560px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--workspace-surface);
  border: 1px solid var(--workspace-border-strong);
  /* 큰 floating surface = 16px — 검색 팝업(.axe-cmdk)과 같은 위계. */
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-xl);
}

.axe-workspace-picker__header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2) var(--space-1) var(--space-4);
  border-bottom: 1px solid var(--workspace-border);
}

.axe-workspace-picker__header > strong {
  min-width: 0;
  overflow: hidden;
  color: var(--workspace-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.axe-workspace-picker__close {
  width: 44px;
  height: 44px;
  display: inline-flex;
  flex: 0 0 44px;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--workspace-muted);
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}

.axe-workspace-picker__list {
  min-height: 0;
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-2);
}

.axe-workspace-picker__label {
  margin: 0;
  padding: var(--space-2) var(--space-3) var(--space-1);
  color: var(--workspace-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
}

.axe-workspace-picker__item {
  width: 100%;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--workspace-text);
  font: inherit;
  font-size: var(--text-sm);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}

/* 라벨(한 줄 span 또는 두 줄 __copy)이 남는 폭을 갖고, 앞뒤 글리프는 제 치수를
 * 지킨다 — 한 규칙으로 세 종류의 행(서비스·entity·계정)을 모두 담는다. */
.axe-workspace-picker__item > span {
  min-width: 0;
  flex: 1 1 auto;
}

.axe-workspace-picker__item > svg {
  flex: 0 0 auto;
}

.axe-workspace-picker__item[aria-current] {
  background: var(--workspace-selected);
}

.axe-workspace-picker__item:focus-visible,
.axe-workspace-picker__close:focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: -2px;
}

/* Context rail -------------------------------------------------------- */

.axe-workspace-context {
  min-width: 0;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  color: var(--workspace-text);
}

/* 슬롯 ⓪(세션)이 패널의 **앞 형제**로 설 때의 높이 되돌림.
 *
 * 위 `min-height: 100%` 는 패널이 호스트를 혼자 채운다는 전제의 값이다 — 도크가
 * `margin-top: auto` 로 바닥에 서려면 패널이 호스트 높이만큼은 자라야 한다.
 * 그런데 호스트(.axe-app-shell__toc = 100vh−topbar 의 `overflow-y: auto` 블록
 * 컨테이너 · 서랍 패널도 동형)에 형제가 하나 더 서면 그 전제가 깨진다: 합계가
 * 100% + 형제 높이가 되어 **세션이 몇 줄이든 레일이 항상 스크롤된다**.
 *
 * 그래서 첫 자식이 아닐 때만 되돌린다. 슬롯 ⓪ 을 패널 **안**의 첫 자식으로
 * 넣은 소비자는 이 규칙에 걸리지 않고 종전 값을 그대로 받는다(계약이 두 자리를
 * 다 허용하므로 가드도 그 두 자리를 다 성립시킨다). 특정도 (0,3,0) 이라
 * 위 base 와 disclosure 패널의 min-height 를 둘 다 이긴다. */
.axe-app-shell__toc > .axe-workspace-context:not(:first-child),
.axe-workspace-disclosure__panel > .axe-workspace-context:not(:first-child) {
  min-height: 0;
}

.axe-workspace-context__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4);
  border-bottom: 1px solid var(--workspace-border);
}

.axe-workspace-context__eyebrow,
.axe-workspace-context__section-title {
  color: var(--workspace-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
}

.axe-workspace-context__title {
  overflow-wrap: anywhere;
  color: var(--workspace-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.axe-workspace-context__summary {
  margin: 0;
  color: var(--workspace-muted);
  font-size: var(--text-xs);
  line-height: 1.55;
}

.axe-workspace-context__tabs {
  min-width: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-bottom: 1px solid var(--workspace-border);
  background: var(--workspace-rail);
}

.axe-workspace-context__tab {
  position: relative;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding-inline: var(--space-1);
  border: 0;
  background: transparent;
  color: var(--workspace-muted);
  font: inherit;
  font-size: var(--text-xs);
  text-decoration: none;
  cursor: pointer;
}

.axe-workspace-context__tab:is(
  [aria-current="page"],
  [aria-selected="true"],
  [data-state="active"]
) {
  color: var(--workspace-text);
}

.axe-workspace-context__tab:not(.axe-tabs__trigger):is(
  [aria-current="page"],
  [aria-selected="true"],
  [data-state="active"]
) {
  box-shadow: inset 0 -2px var(--workspace-blue);
}

.axe-workspace-context__tab:focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: -2px;
}

.axe-workspace-context__body {
  min-width: 0;
  flex: 1 1 auto;
  padding: var(--space-4);
}

.axe-workspace-context__section-title {
  margin: 0 0 var(--space-3);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
}

.axe-workspace-context__link {
  position: relative;
  min-height: 32px;
  display: flex;
  align-items: center;
  margin-left: -1px;
  padding: var(--space-1) var(--space-3);
  border-left: 2px solid transparent;
  color: var(--workspace-muted);
  font-size: var(--text-sm);
  line-height: 1.4;
  text-decoration: none;
}

.axe-workspace-context__link:is(
  [aria-current="page"],
  [aria-current="location"]
) {
  color: var(--workspace-text);
  border-left-color: var(--workspace-blue);
}

.axe-workspace-context__link:focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: 1px;
  border-radius: var(--radius-sm);
}

.axe-workspace-context__footer {
  min-height: 48px;
  margin-top: auto;
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--workspace-border);
  color: var(--workspace-muted);
  font-size: var(--text-xs);
}

/* Context rail — ContextPanel@1 슬롯 스택 -------------------------------
 *
 * 계약: src/lib/contracts/context-panel/contract.v1.json (`ContextPanel@1`).
 * 한 문서에 패널이 두 벌 렌더된다(≥1440 = toc 사본, <1440 = 서랍 사본). 인스턴스
 * 핸들 data-axe-ctx="toc|drawer" 는 **셸이 소유하는 호스트 요소**에 붙고 패널
 * 콘텐츠에는 인스턴스에 의존하는 바이트가 없다 — 그래서 슬롯 ①② 는 두 사본이
 * 바이트 동일하다. 아래가 그 스택의 자리이며 순서가 계약이다:
 *
 *   (셸 호스트: .axe-app-shell__toc | .axe-workspace-disclosure__panel)
 *   ⓪ sessions  세션 구역. 선택적 · **우측 패널의 첫 시각 요소**.
 *   .axe-workspace-context
 *   ├─ ⓪ sessions  (같은 슬롯을 패널 안 첫 자식으로 둔 갈래)
 *   ├─ __help    ① 항상. 접힘 없음.
 *   ├─ __prompt  ② 프롬프트 카드 1장. 조건부.
 *   ├─ __dock    ③ 하단 sticky 도크. 조건부(chat 서빙 소비자만).
 *   └─ __footer  ④ 패널을 닫는 한 줄(⌘K 안내). 조건부 · 언제나 마지막.
 *
 * **이 다섯이 닫힌 목록이다(0.39.0)** — 패널 직계 자식이 이 밖이면 소비자
 * conformance 가 red 다. 세 클래스의 상호 순서만 말하고 "그 밖에 무엇이 설 수
 * 있는가" 를 비워 두었던 것이 슬롯 ⓪ 표류를 낳은 것과 같은 침묵이라, 좌측 레일의
 * rail-composition 계약과 같은 결론으로 닫는다(contract.v1.json `slots.closed`).
 *
 * 슬롯 ⓪ 은 0.38.3 의 가산 개정이다(운영자 재정: "우측 패널에서 항상 세션이 맨
 * 위로, 다른 컨텐츠 다 밑으로"). 전용 클래스가 없다 — 자리가 곧 계약이고 재료는
 * 세션 어휘(.axe-session-head + .axe-session-list--compact)다. 성립하는 자리는
 * 둘: `.axe-workspace-context` 의 **첫 자식**이거나 **그 앞 형제**. 어느 쪽이든
 * 세션 구역보다 먼저 나오는 시각 요소는 없다 — 배너·헤더·프롬프트 카드·페이지
 * 섹션 전부 뒤다. ①②③ 의 상호 순서는 불변이고, ⓪ 은 그 앞에 서는 새 불변식이다.
 * 앞-형제 갈래의 부작용(패널 min-height 100% + 형제 높이 = 상시 스크롤)은 위
 * `.axe-workspace-context:not(:first-child)` 가드가 되돌린다.
 *
 * **두 자리 모두 킷이 여백을 준다.** 앞-형제 갈래는 소비자가 `__body` 로 감싸
 * 그 클래스의 16px 을 받고(패널 밖이라 `flex: 1 1 auto` 가 아무것도 먹지 않는다),
 * 패널 **안** 첫-자식 갈래는 바로 아래 규칙이 세션 어휘에 직접 준다. 소비자가
 * 로컬 padding 을 세우지 않는다 — 그 순간 여백값이 서비스마다 갈린다.
 *
 * 첫-자식 갈래에서 `__body` 로 감싸지 **말 것**: 그 클래스는 `flex: 1 1 auto` 라
 * 패널 안 첫 자식으로 서면 남는 높이를 통째로 먹어 ①help 를 바닥으로 밀어낸다
 * (패널이 세로 flex 라 그렇다 — 앞-형제 자리에서는 부모가 다르므로 무해하다).
 * `__body` 가 패널 **안**에 정당하게 서는 경우는 그것이 패널의 본문 영역 자체일
 * 때뿐이고(cortex·index), 그때는 세션이 그 본문의 첫 요소로 들어간다.
 *
 * 슬롯이 비면 **노드를 내지 않는다** — 빈 카드·placeholder 금지. 그래서 여기에
 * min-height 를 주지 않는다(빈 자리가 보이는 순간 계약 위반이 시각으로 샌다).
 *
 * 도크는 in-flow sticky 다. 오버레이로 띄우지 말 것 — 오버레이하는 순간 그것은
 * 도크가 아니라 탭이고, ①② 를 가려 슬롯 순서 불변식이 깨진다.
 *
 * kit 은 이 표면의 JS 를 배포하지 않는다. 도크 노드를 활성 사본으로 옮기는
 * mover 와 복사 훅은 소비자(gate) 소유다 — 규약은 contract.v1.json 의
 * `dom.dock` · `dom.copy` 가, 기계 강제는 gate 의 jsdom 하네스가 진다. */

/* ── 슬롯 ⓪ 안쪽 여백 — 패널 **안** 첫-자식 갈래 (0.38.4) ──────────────────
 *
 * `.axe-workspace-context` 는 padding 이 0 이다(여백은 슬롯마다 자기가 든다).
 * ①②③ 은 그 규약대로 `__help`·`__prompt`·`__dock` 이 각자 16px 을 들고 있는데,
 * ⓪ 은 전용 슬롯 클래스가 없어서(자리가 곧 계약) 0.38.3 계약이 허용한 두 자리 중
 * **첫-자식 갈래만 여백 없이 열려 있었다** — 옮기는 순간 세션 구역이 레일
 * 가장자리에 붙는다(gate 실측 보고, 0.38.3 수신 중). 그 자리에 재료를 준다.
 *
 * **소비자 마크업 셋을 다 집는 방식**으로 적는다. 세션 어휘는 래퍼 없이 평평하게
 * (gate: `head` · `ul` · 빈-줄 `__summary` 가 전부 패널 직계 자식) 서기도 하고,
 * 래퍼 하나에 담겨(cortex·index: `__body`, 또는 맨 `div`) 서기도 한다. 한 모양만
 * 집으면 다음 재벤더에서 조용히 갈리므로 **둘 다** 이름으로 집는다:
 *   · 평평한 갈래 = 패널 직계 자식인 세션 어휘 자체(`head`/`list`/빈-줄 `summary`)
 *   · 감싼 갈래  = `:has(> .axe-session-head)` 인 패널 직계 자식
 *
 * 감싼 갈래에 `__body`/`__help` 제외 가드를 두지 않는 이유: 패널 직계 자식 중
 * 세션 머리를 **직계로** 담을 수 있는 킷 클래스는 `__body` 뿐이고, 그것은 이미
 * 같은 `var(--space-4)` 를 들고 있다 — 규칙이 겹쳐도 값이 같아 아무것도 바뀌지
 * 않는다(index 실측). 가드를 붙이면 특정도만 올라가고 얻는 것이 없다.
 *
 * 세로 여백은 **run 의 양 끝에만** 준다. 가운데 조각에 위아래를 주면 머리와 목록
 * 사이가 16+16 으로 벌어진다 — 그 사이 간격은 `.axe-session-head` 의 margin-bottom
 * 8px 이 이미 정본으로 쥐고 있다. 아래쪽은 뒤따르는 슬롯이 자기 16px 로 잇고
 * (①help 는 계약상 항상 존재하므로 평시에는 이 자리가 곧 그 갈래다), ⓪ 이 정말
 * 패널의 마지막이면 `:last-child` 가 바닥을 깐다.
 *
 * **상단만 값이 다르다 — `var(--space-2)`(0.38.6).** 세로 여백의 위쪽은 아래쪽·
 * 가로와 목적이 다르다: 아래·가로는 슬롯을 이웃과 떼는 간격이지만, 위쪽은 셸의
 * **두 기둥이 같은 높이에서 시작하는가**를 정한다. 좌측 내비(`.axe-workspace-
 * rail__nav`)는 브랜드 행 바로 아래 `padding-block-start: var(--space-2)` 로
 * 열리는데(운영자 승인 디자인), 우측이 16 이면 같은 상단바 아래에서 우측 첫
 * 요소만 2배 낮게 시작한다 — 실측 1440×900 에서 좌측 첫 요소는 브랜드 행 아래
 * 9px, 우측 세션 머리 제목은 상단바 아래 18.5px 였다(운영자 vision 보고:
 * "우측 패널 위 여백이 여전히 많다"). 그래서 상단 인셋만 좌측과 **같은 토큰**을
 * 쓴다. 8 이라는 숫자가 아니라 `--space-2` 라는 토큰이 계약이다 — 좌측이 움직이면
 * 우측도 같이 움직여야 두 기둥이 갈리지 않는다.
 *
 * 머리의 터치 타깃은 이 변경과 무관하다. `.axe-session-head` 는 타깃이 아니라
 * 구역 머리이고(높이도 min-height 가 아니라 내용 28px + 이 패딩의 합이었다),
 * 실제 타깃인 `.axe-session-head__button` 은 종전대로 28px 다 — 그 28px 는 레일
 * brand 행 리듬을 따르는 의도된 값이고(위 규칙의 근거 주석), coarse 포인터에서도
 * 이 표면은 44px 로 자라지 않는다. 래퍼 갈래(`__body`)의 머리는 이 변경 전에도
 * 28px 였으므로 세 갈래가 이제 같은 높이로 수렴한다.
 *
 * 특정도: 네 선택자 모두 (0,2,0) — `.axe-session-list{padding:0}`(0,1,0) 과
 * `.axe-workspace-context__body{padding:…}`(0,1,0) 을 순서와 무관하게 이긴다.
 * shorthand 대 longhand 는 특정도가 갈리면 캐스케이드가 먼저 정하므로, 아래
 * `padding-inline` 은 위 `padding` 단축과 다투지 않는다. */
.axe-workspace-context > :is(
  .axe-session-head,
  .axe-session-list,
  .axe-workspace-context__summary
),
.axe-workspace-context > :has(> .axe-session-head) {
  padding-inline: var(--space-4);
}

.axe-workspace-context > :is(
  .axe-session-head,
  .axe-workspace-context__summary
):first-child,
.axe-workspace-context > :has(> .axe-session-head):first-child {
  padding-block-start: var(--space-2);
}

.axe-workspace-context > :is(
  .axe-session-list,
  .axe-workspace-context__summary
):last-child,
.axe-workspace-context > :has(> .axe-session-head):last-child {
  padding-block-end: var(--space-4);
}

/* ── 슬롯 ⓪ 세로 여백 이중화 방지 — 호스트가 자체 세로 패딩을 줄 때 (0.38.5) ──
 *
 * 위 슬롯 ⓪ 세로 여백은 "패널이 세로 여백을 안 주는 자리" 를 위한 재료다. 그런데
 * 셸 호스트 중 base `.axe-app-shell__toc` 는 문서 TOC 용 `padding: var(--space-5)
 * var(--space-4)`(세로 24px)를 스스로 들고 있어, 그 안에 세션 run 이 서면 호스트
 * 24px + 슬롯 16px = 40px 로 상단이 이중이 된다(운영자 vision 보고). 호스트가
 * 세로 여백을 이미 주는 자리에서는 그것을 **슬롯에 양보**해 단일 층(슬롯 상단
 * 인셋)으로 수렴시킨다 — 그러면 세로 패딩이 0 인 다른 호스트(서랍 패널 ·
 * `.axe-workspace-shell .axe-app-shell__toc { padding: 0 }` 로 이미 지워진 워크스페이스
 * 셸 toc)와 상단 여백이 일치한다(0.38.6 부터 그 값은 `var(--space-2)`).
 *
 * **가로는 건드리지 않는다** — `padding-block` 만 0 으로 눕히므로 base toc 의
 * `padding-inline: var(--space-4)` 는 그대로 남고, 세션 머리 제목·행 x 는 종전
 * 그대로다(문서 TOC 인셋과 값이 같아 무해했던 가로는 이중이 아니었다).
 *
 * `:has(.axe-session-head)` 로 **세션 run 이 실제로 선 호스트만** 집는다 — 순수
 * 문서 TOC(세션 없음)는 자기 세로 패딩을 그대로 지킨다. 특정도 (0,2,0) 이라
 * base `.axe-app-shell__toc`(0,1,0) 의 padding 단축을 padding-block 만 덮고(가로는
 * 단축이 유지), 워크스페이스 셸 reset(0,2,0)과는 같은 0 을 써 충돌이 없다. 서랍
 * 패널은 세로 패딩이 0 이라 이 규칙이 무변경(no-op)이되, 두 호스트에 같은 불변식을
 * 명문화해 이후 서랍에 패딩이 붙어도 이중이 재발하지 않게 한다. */
.axe-app-shell__toc:has(.axe-session-head),
.axe-workspace-disclosure__panel:has(.axe-session-head) {
  padding-block: 0;
}

/* ── 슬롯 ⓪ 상단 인셋 — 패널의 **앞 형제** 갈래 (0.38.6) ────────────────────
 *
 * 위 상단 인셋은 슬롯 ⓪ 이 `.axe-workspace-context` **안**에 설 때의 재료다.
 * 계약이 허용한 다른 자리 — 셸 호스트 안에서 패널의 **앞 형제**(blueprint:
 * `aside.axe-app-shell__toc > section.axe-workspace-context__body`, 서랍에서는
 * 같은 섹션이 `.axe-workspace-disclosure__panel` 직계) — 는 `__body` 자신의
 * `padding: var(--space-4)` 에서 상단을 받아 왔다. 그래서 상단만 16 으로 남아
 * 갈래마다 시작 높이가 갈렸다(실측: 세 갈래 모두 제목 top 74.5 였다가, 안쪽
 * 갈래만 8 로 내려가면 앞-형제 갈래가 혼자 74.5 에 남는다).
 *
 * `__body` 는 레일 밖에서도 쓰는 **범용 본문 클래스**라 그 클래스의 상단 여백을
 * 전역으로 줄이지 않는다 — `:has(> .axe-session-head)` 로 **세션 머리를 직계로
 * 담은 경우만** 집고, 셸 호스트 둘로 한 번 더 좁혀 "슬롯 ⓪ 의 앞-형제 자리"
 * 라는 계약을 선택자가 그대로 읽히게 한다. 하단·가로는 건드리지 않는다
 * (`padding-block-start` longhand) — 이 개정이 정하는 것은 상단 하나다.
 *
 * 패널 **안** 첫-자식으로 선 `__body`(cortex·index 의 본문 영역)는 위
 * `.axe-workspace-context > :has(> .axe-session-head):first-child` 규칙이 이미
 * 같은 `var(--space-2)` 를 주므로 여기서 다시 집지 않는다.
 *
 * 특정도 (0,3,0) — `:is()` 는 인자 중 최대치(0,1,0)를 쓰므로 호스트 + `__body` +
 * `:has()` 로 셋이다. `.axe-workspace-context__body{padding:…}`(0,1,0) 단축을
 * 순서와 무관하게 이긴다. */
:is(
  .axe-app-shell__toc,
  .axe-workspace-disclosure__panel
) > .axe-workspace-context__body:has(> .axe-session-head) {
  padding-block-start: var(--space-2);
}

.axe-workspace-context__help {
  min-width: 0;
  flex: 0 1 auto;
  padding: var(--space-4);
}

.axe-workspace-context__prompt {
  min-width: 0;
  flex: 0 0 auto;
  padding: 0 var(--space-4) var(--space-4);
}

/* margin-top:auto = 위 슬롯이 짧으면 바닥에 선다. sticky bottom = 길면 스크롤에
 * 붙어 남는다. 둘은 같은 목적의 두 상황이지 중복이 아니다. 배경은 레일 색을 다시
 * 선언한다 — sticky 로 떠 있는 동안 아래 내용이 비쳐서는 안 된다. */
.axe-workspace-context__dock {
  position: sticky;
  bottom: 0;
  z-index: 1;
  min-width: 0;
  flex: 0 0 auto;
  margin-top: auto;
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--workspace-border);
  background: var(--workspace-rail);
}

/* 프롬프트 카드 — 외부 AI 에 붙여넣을 블록의 미리보기·복사면.
 *
 * 복사 대상은 __slot 하나뿐이다. 고지(__notice)와 상태(__status)는 복사 타깃
 * **바깥**이며, label 도 복사 텍스트에 들어가지 않는다(계약 §copy.excluded). */
.axe-prompt-card {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--workspace-border);
  border-radius: var(--radius-md);
  background: var(--workspace-surface);
}

/* 미리보기 한 줄. 계약 텍스트의 개행은 조판 줄바꿈이라 여기서는 흘려보낸다
 * (280px 레일에서 하드랩을 보존하면 톱니처럼 읽힌다). 바이트는 __slot 과 골든이
 * 지킨다. */
.axe-prompt-card__line {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--workspace-text);
  font-size: var(--text-xs);
  line-height: 1.55;
}

/* 복사 원본 — **보이고 선택 가능해야 한다**(K3). display:none 버퍼로 만들면
 * 클립보드 API 가 막힌 환경에서 사용자에게 남는 경로가 0 이 된다. 여기 담기는
 * 문자열이 곧 골든 벡터의 바이트라 개행을 보존한다. */
.axe-prompt-card__slot {
  min-width: 0;
  max-block-size: 14rem;
  overflow: auto;
  padding: var(--space-2);
  border: 1px solid var(--workspace-border);
  border-radius: var(--radius-sm);
  background: var(--workspace-canvas);
  color: var(--workspace-text);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  user-select: text;
}

/* 트리거. 비활성은 disabled 가 아니라 aria-disabled 다 — disabled 는 포커스를
 * 뺏어 K4(포커스 불변)를 깬다. */
.axe-prompt-card__copy {
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding-inline: var(--space-3);
  border: 1px solid var(--workspace-border);
  border-radius: var(--radius-sm);
  background: var(--workspace-surface);
  color: var(--workspace-text);
  font: inherit;
  font-size: var(--text-xs);
  text-decoration: none;
  cursor: pointer;
}

.axe-prompt-card__copy[aria-disabled="true"] {
  color: var(--workspace-muted);
  cursor: default;
}

.axe-prompt-card__copy:focus-visible {
  outline: 2px solid var(--workspace-blue);
  outline-offset: 1px;
}

/* role="status" live region. 성공·실패 **둘 다** 여기로 announce 된다(K2).
 * 비어 있을 때 자리를 잡지 않는다 — :empty 를 감추지 않고 높이를 안 잡는 것으로
 * 족하다(노드가 살아 있어야 SR 이 이후 변경을 읽는다). */
.axe-prompt-card__status {
  margin: 0;
  min-width: 0;
  color: var(--workspace-muted);
  font-size: var(--text-xs);
  line-height: 1.5;
}

/* 고지문 — 복사 타깃 밖. 한 블록 = 한 문단이고, 계약 텍스트 안의 개행은
 * 조판 줄바꿈이라 흘려보낸다. */
.axe-prompt-card__notice {
  margin: 0;
  min-width: 0;
  color: var(--workspace-muted);
  font-size: var(--text-xs);
  line-height: 1.55;
}

.axe-prompt-card__notice + .axe-prompt-card__notice {
  margin-top: var(--space-2);
}

/* 협업 세션 — 목록(.axe-session-list) + 게재물(.axe-session-post) ---------
 *
 * 같은 어휘가 두 자리에 선다: 우측 컨텍스트 레일의 세션 목록과, 작업면의 게재물
 * 피드. 그래서 재료는 --workspace-… 를 직접 읽지 않고 셸이 이미 aliasing 해 둔
 * 의미 토큰(--text-…, --bg-…, --border-…)만 읽는다 — 레일에 놓으면 workspace
 * 재료를, 캔버스나 셸 밖에 놓으면 전역 재료를 그 자리에서 받는다. 색을 두 벌
 * 쓰지 않으므로 다크 오버라이드도 없다(토큰의 light-dark() 가 처리).
 *
 * 마크업 계약 — CSS-only 소비자(gate·cortex 의 maud)가 손으로 조립하므로
 * 클래스 이름만이 아니라 **태그와 순서까지** 계약이다. 단 그 규칙은 **목록**
 * (ul/li/a/span)에 걸리는 것이고, 머리의 타이틀 태그는 예외다(규약 7):
 *
 *   <div class="axe-session-head">                            ← 선택(목록 머리)
 *     <h2 class="axe-workspace-context__section-title">세션</h2>  ← 태그는 예시
 *     <div class="axe-session-head__actions">
 *       <details class="axe-session-head__new">
 *         <summary class="axe-session-head__button"
 *                  aria-label="새 세션">…plus svg…</summary>
 *         <form class="axe-session-head__new-panel" method="post" action="…">
 *           <input class="axe-input" type="text" name="name" required
 *                  maxlength="400" aria-label="새 세션 이름">
 *           <button class="axe-btn axe-btn--sm" type="submit">만들기</button>
 *         </form>
 *       </details>
 *       <a class="axe-session-head__button" href="…"
 *          aria-label="세션 목록">…preset svg…</a>
 *     </div>
 *   </div>
 *
 *   <ul class="axe-session-list">                              ← 기본 = 두 줄 행
 *     <li class="axe-session-item axe-session-item--active">
 *       <!-- aria-label 없음: 자손 텍스트(이름+메타)가 접근 이름이다(규약 5).
 *            상태 배지도 없음 — 무표기가 곧 진행 중(marked-exception). -->
 *       <a class="axe-session-item__link" href="…" aria-current="page">
 *         <span class="axe-session-item__dot axe-session-item__dot--active"
 *               aria-hidden="true"></span>
 *         <span class="axe-session-item__name">세션 이름</span>
 *         <span class="axe-session-item__meta">AXEC · 2시간 전 · 게재 3</span>
 *       </a>
 *       <div class="axe-session-item__actions">…버튼…</div>   ← 선택
 *     </li>
 *   </ul>
 *
 *   <ul class="axe-session-list axe-session-list--compact">    ← 레일 = 한 줄 행
 *     <li class="axe-session-item">
 *       <!-- __meta 가 없어 도트가 유일한 상태 신호 → aria-label 의무(규약 5). -->
 *       <a class="axe-session-item__link" href="…"
 *          aria-label="세션 이름 — 완료" title="AXEC · 2시간 전 · 게재 3">
 *         <span class="axe-session-item__dot axe-session-item__dot--done"
 *               aria-hidden="true"></span>
 *         <span class="axe-session-item__name">세션 이름</span>
 *       </a>
 *     </li>
 *   </ul>
 *
 *   <!-- 같은 레일, 목록이 비었을 때(설정은 되어 있고 0행) — 규약 9. 머리는 남는다. -->
 *   <p class="axe-workspace-context__summary">아직 세션이 없습니다.</p>
 *
 *   <article class="axe-session-post">
 *     <header class="axe-session-post__head">
 *       <span class="axe-session-post__author">강수훈</span>
 *       <span class="axe-session-post__origin axe-badge axe-badge--info">claude-code@mac-mini</span>
 *       <time class="axe-session-post__time" datetime="…">08-27 14:02</time>
 *     </header>
 *     <div class="axe-session-post__body axe-prose">…markdown…</div>
 *     <!-- 또는 렌더러가 없으면 -->
 *     <pre class="axe-session-post__body axe-session-post__body--plain">…원문…</pre>
 *   </article>
 *
 * 규약 아홉:
 *   1. 행 = <li>(.axe-session-item), 클릭면 = 그 안의 <a>/<button>
 *      (.axe-session-item__link). 액션 버튼이 링크의 형제로 서야 하므로 둘을
 *      나눈다 — <a> 안에 <button> 을 넣는 마크업은 유효하지 않다.
 *   2. 현재 열린 세션은 행의 --active **와** 링크의 aria-current="page" 를
 *      **둘 다** 준다. 어느 쪽이든 배경 tint 를 칠하지만, 시각만 있고 aria 가
 *      없으면 SR 사용자에게 현재 위치가 사라진다.
 *   3. __origin 은 자리(flex 위치)만 준다. 배지로 보이려면 .axe-badge 를 함께
 *      붙인다 — 배지 선언이 이 파일보다 뒤(components.css)에 오므로 재료는
 *      배지가 이긴다. 배지 없이 써도 mono 한 줄로 읽힌다.
 *   4. 이 계약은 **버튼 재료를 주지 않는다**. __actions 안의 버튼과 __body 안의
 *      마크다운 조판은 기존 클래스(.axe-workspace-bar__icon-button, .axe-prose)
 *      를 조립해 쓴다. 게재물 여러 장을 세로로 쌓는 피드 컨테이너도 신설하지
 *      않는다 — .axe-stack.axe-stack--gap-4 로 족하다.
 *      __actions 둘(머리·행)은 **<div>** 다. 규약 1 과 같은 근거로, <span> 은
 *      phrasing content 만 담을 수 있어 안에 <details> 를 넣는 순간 마크업이
 *      무효가 된다(머리의 생성 폼이 바로 그것이고, 행의 이름변경도 같은 수단을
 *      쓸 수 있다). display 는 어차피 CSS 가 정하므로 잃는 것이 없다.
 *      **행 액션의 재료는 글자가 아니라 아이콘이다** — @axe/ui 의 RenameIcon ·
 *      CopyIcon(16 단위 상자 · 1.5 획, CSS-only 는 그 d= 를 복사)을
 *      .axe-workspace-bar__icon-button 에 얹으면 아래 28px 캡이 정사각으로
 *      세운다. 글자 라벨도 서기는 하지만 __actions 는 opacity 로만 숨어
 *      **숨은 동안에도 폭을 점유**하므로, "이름"·"복사" 두 짝이면 ~100px 이
 *      모든 행에서 세션 이름의 말줄임을 그만큼 앞당긴다(아이콘 두 짝은 56px).
 *      동작은 aria-label 이 진다.
 *   5. __dot 은 목록 행에서 __link 의 **첫 자식**이고 언제나 aria-hidden="true" 다.
 *      (목록 밖 — 상세 페이지의 상태 한 줄 같은 글 흐름 — 에도 그대로 놓을 수
 *      있다. 도트가 inline-block 을 스스로 들고 있어 flex/grid 자식이 아니어도
 *      8px 원이 선다.) 도트는
 *      색 하나로만 말하므로 상태를 글로도 지는 짝이 필요한데, **그 짝은 조판마다
 *      다르다**:
 *        · --compact 행 = __meta 가 없어 도트가 유일한 상태 신호다. 그러니
 *          __link 에 aria-label="{세션 이름} — 진행 중|완료" 를 **의무**로 준다.
 *        · 기본(두 줄) 행 = **aria-label 을 걸지 않는다.** aria-label 은 자손
 *          텍스트를 *덮으므로*, 걸는 순간 눈에 보이는 __meta(entity·시각·게재수·
 *          배지)가 접근 이름에서 통째로 사라진다 — 상태 한 조각을 얻자고 나머지
 *          전부를 잃는 거래다. 여기서는 자손 텍스트가 접근 이름의 정본이고,
 *          상태는 __meta 안의 가시 배지·텍스트가 진다.
 *      기본 행의 그 상태 텍스트는 **비-기본 상태(완료·보관)에만** 배지로 세운다 —
 *      **무표기가 곧 진행 중**이다(marked-exception 관례, blueprint 보드 선례).
 *      전 행에 "진행 중" 배지를 달면 대부분의 행이 같은 말을 반복해 목록이 소음이
 *      된다. 이 관례는 시각과 SR 에 **똑같이** 적용된다: 배지가 없는 행은 양쪽
 *      모두에게 진행 중이므로, active 행에 상태 텍스트가 없는 것은 누락이 아니라
 *      계약이다(도트는 그 관례의 시각적 요약일 뿐 유일한 신호가 아니다).
 *      상태→변형은 active→--active · done→--done · archived→--archived 로 1:1.
 *      마크업은 두 조판이 같고, 조판만 CSS 가 가른다: 기본(두 줄) 행은 도트가
 *      있으면 grid 로 전환돼 도트·이름이 첫 줄, __meta 가 둘째 줄 전폭에 선다
 *      (세로 flex 그대로면 도트가 이름 위 딴 줄에 서기 때문). :has() 미지원
 *      브라우저는 그 옛 동작으로 남는다 — 점진 향상.
 *      --active 와 --done 은 채움 vs 빈 원이라 색을 빼도 형태로 갈리지만,
 *      --archived 는 --active 와 채움이 같아 **색 하나로만** 갈린다. 그래서
 *      보관 도트는 단독으로 쓰지 않는다 — 가시 상태 텍스트(배지 등)를 반드시
 *      병기하고, 도트는 그 텍스트의 장식으로 둔다. 그 병기가 설 자리가 __meta 라
 *      보관은 기본 행의 것이다(위 두 규칙이 같은 방향을 가리킨다: 가시 배지가
 *      상태를 지므로 aria-label 이 필요 없고, aria-label 이 없으므로 그 배지가
 *      접근 이름에 그대로 실린다).
 *   6. --compact 행은 __meta 를 **아예 내지 않는다**(빈 노드도 두지 않는다).
 *      메타는 __link 의 title 로 옮긴다 — 한 줄 행에 두 번째 줄을 숨기는 것이
 *      아니라 처음부터 만들지 않는 것이 계약이다. title 은 메타의 **정본이 아니라
 *      포인터 사용자의 지름길**이다: 정본은 클릭 한 번 거리의 상세·목록 페이지에
 *      가시 __meta 로 서므로, title 이 SR·터치에 닿지 않는 것이 이 자리에서는
 *      결손이 아니다(행이 반드시 져야 하는 이름·상태는 __name 과 aria-label 이
 *      진다). __actions 는 그대로 쓰되 compact 안에서는 28px 리듬이다 —
 *      modifier 가 액션 요소의 **높이를** 28px 로 캡하고 폭은 auto + 28px 바닥만
 *      깐다. 아이콘 재료는 28px 정사각이 되고, 글자 재료("이름"·"복사"·"복사됨")는
 *      제 폭대로 선다(폭까지 못 박으면 그 라벨이 잘린다). <details><summary> 로
 *      세운 액션도 같은 캡을 받는다.
 *   7. 머리(.axe-session-head)는 선택이다. 제목은 기존
 *      .axe-workspace-context__section-title 을 그대로 쓰고, 이 행이 그 제목의
 *      아래 여백을 대신 가져간다(그래야 제목과 아이콘의 세로 중심이 맞는다).
 *      **타이틀 요소는 소비자가 정한다**(h2·p·div…) — 계약은 클래스와 head 행
 *      배치이지 태그가 아니다. 위 예시의 <h2> 는 예시일 뿐이며, 실제 태그는 그
 *      페이지의 문서 개요(heading 레벨)가 결정한다: 같은 어휘가 어떤 화면에서는
 *      섹션 제목이고 어떤 화면에서는 레일의 라벨이라, 태그를 여기서 고정하면
 *      한쪽의 개요가 반드시 틀어진다. 실제로 소비자 셋이 각각 p·div·h2 로 선다.
 *   8. 생성 폼(.axe-session-head__new)은 네이티브 <details> 다 — JS 0 인 소비자가
 *      여닫을 수 있는 유일한 수단이고, 상태가 DOM 에 있으면 React 소비자도 같은
 *      마크업을 쓴다. 규약 4 는 여기서도 유효하다: 입력·제출 재료는 새로 만들지
 *      않고 .axe-input · .axe-btn 을 조립한다.
 *   9. **빈 목록은 계약이다.** compact 레일에서 목록이 비면(설정은 되어 있고
 *      0행) <ul> 을 빈 채로 내지 말고 그 자리에
 *      <p class="axe-workspace-context__summary">아직 세션이 없습니다.</p> 를
 *      세운다. 머리(.axe-session-head)는 그대로 남는다 — 생성 버튼은 목록이
 *      비었을 때 가장 필요하다. 빈 공간은 "아직 없다" 가 아니라 **"고장났다"**
 *      로 읽히고(구역 제목만 있고 아래가 비면 로딩 실패와 구분되지 않는다),
 *      문안까지 못 박는 이유는 소비자마다 다른 말을 세우면 같은 셸의 같은
 *      자리가 서비스마다 다른 제품처럼 보이기 때문이다. 세션을 아예 서빙하지
 *      않는 표면은 이 문구가 아니라 섹션 전체를 내지 않는다 — "없음" 과
 *      "해당 없음" 은 다른 말이다. 새 재료는 없다: 안내 한 줄은 레일이 이미
 *      쓰는 __summary 이고, 이 계약이 정하는 것은 그 자리와 문안뿐이다. */

/* 목록 머리 — 제목 왼쪽, 액션 아이콘 오른쪽. 제목이 자기 아래 여백을 들고 있으면
 * 아이콘과 세로 중심이 어긋나므로 그 여백을 이 행이 가져간다. */
.axe-session-head {
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin: 0 0 var(--space-2);
}

/* 세션 머리의 제목은 **제목 위계**다 — 페이지 섹션 캡션(eyebrow류)이 아니다.
 * 같은 `.axe-workspace-context__section-title` 어휘가 두 자리에 서는데(head 항목
 * 계약: "같은 어휘가 어떤 화면에서는 섹션 제목이고 어떤 화면에서는 레일 라벨"),
 * base 규칙은 eyebrow 와 선언을 공유해(mono · text-xs · uppercase · 자간 ·
 * muted) 페이지 캡션에 맞춘다. 그 재료가 세션 레일 머리에 오면 한글 "세션" 이
 * mono·초소형·muted 라 어색하고 영문이면 SESSIONS 로 대문자화된다 — 레일의
 * 제목 위계와 어긋난다. 그래서 이 자리에서만(`.axe-session-head` 안, 특정도
 * (0,2,0) 로 base (0,1,0) 을 이긴다) eyebrow 공유 선언을 덮어 `.axe-workspace-
 * context__title`·레일 행 이름과 같은 눈금(sans · text-sm · workspace-text)으로
 * 세운다. **다른 자리의 __section-title(페이지 섹션 캡션)은 불변** — 이 오버라이드는
 * `.axe-session-head` 스코프 안에서만 성립한다. */
.axe-session-head .axe-workspace-context__section-title {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  letter-spacing: 0;
  text-transform: none;
  color: var(--workspace-text);
}

.axe-session-head__actions {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

/* 28px 아이콘 버튼 — 레일 brand 행(검색·접기 토글)의 28px 리듬을 그대로 받는다.
 * bar 의 44px 아이콘 버튼이 아닌 이유는 여기가 화면 크롬이 아니라 레일 안 한
 * 구역의 머리이기 때문이다: 44px 를 놓으면 한 줄짜리 제목이 버튼 높이에 끌려
 * 구역 사이 간격이 무너진다.
 *
 * list-style 을 지우는 이유는 <summary> 도 이 클래스를 받아야 하기 때문이다 —
 * CSS-only 소비자는 "새 세션" 폼을 <details> 로 여닫고, 그때 트리거가 곧 이
 * 버튼이다(::-webkit-details-marker 는 list-style 로 지워지지 않는다). */
.axe-session-head__button {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-tertiary);
  list-style: none;
  cursor: pointer;
}

.axe-session-head__button::-webkit-details-marker {
  display: none;
}

.axe-session-head__button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* 비활성 — author color 를 준 순간 UA 의 회색은 지므로, 흐림은 이쪽이 직접
 * 말해야 한다. 색을 한 벌 더 두지 않고 opacity 로 낮추는 이유는 이 버튼이
 * currentColor 로 그린 svg 를 담기 때문이다: 글리프까지 한 번에 물러난다.
 *
 * 네이티브 button[disabled] 는 포커스를 받지 못하므로 키보드 사용자는 이 버튼에
 * 닿지 못한다. 따라서 **비활성 사유는 이 버튼이 아닌 곳이 져야 한다** — 레일의
 * 안내 문구처럼 인접한 가시 텍스트가 맡는다. 사유를 버튼 자신이 지고 포커스로도
 * 발견돼야 하는 표면이라면 소비자가 aria-disabled 를 택한다. 그 선택이 재료를
 * 잃는 일이 되지 않도록 두 표기에 같은 시각을 주며, 링크로 세운 버튼은
 * :disabled 가 아예 성립하지 않아 aria-disabled 가 유일한 표기이기도 하다.
 *
 * 다만 aria-disabled 는 **상태를 전달할 뿐 아무것도 막지 않는다** — 클릭 핸들러도,
 * 링크의 네비게이션도, <summary> 의 토글도 그대로 산다. 킷이 주는 것은 시각과
 * 의미까지이고 **활성 억제는 소비자 의무**다: 핸들러 진입에서 가드하고, 링크·
 * summary 면 기본동작을 막는다. 억제 구현 없이 aria-disabled 만 붙이면 "못 누른다"
 * 고 말해 놓고 눌리는 표면이 되므로 금지한다.
 *
 * 여기서 pointer-events: none 을 깔지 않는 이유도 같다. 그것은 마우스만 막고
 * 키보드 활성(포커스 후 Enter/Space)은 그대로 두는 **반쪽 억제**라, 억제한 줄 알고
 * 넘어가게 만든다 — 아무것도 안 막는 것보다 나쁜 거짓이다(게다가 cursor 선언과
 * hover 피드백까지 함께 죽는다). */
.axe-session-head__button:disabled,
.axe-session-head__button[aria-disabled="true"] {
  opacity: 0.45;
  cursor: default;
}

/* [+] 의 생성 폼 — 네이티브 <details>. JS 0 인 소비자(maud·jinja)가 여닫을 수
 * 있는 유일한 수단이고, React 소비자도 같은 마크업을 쓴다(상태가 DOM 에 있으면
 * 두 렌더러가 갈라지지 않는다).
 *
 * .axe-workspace-disclosure__panel 과 정신은 같되 조판이 다르다: 저쪽은 화면
 * 가장자리에 붙는 fixed 전면 서랍이고, 이쪽은 트리거에 앵커된 소형 팝오버다.
 * 그래서 relative 컨테이너가 필요하고(absolute 의 기준), 오른쪽 끝에 맞춘다 —
 * 머리 행의 액션은 항상 레일 오른쪽 끝에 서므로 왼쪽으로 열어야 잘리지 않는다. */
.axe-session-head__new {
  position: relative;
  display: inline-flex;
}

/* 열린 트리거 = 눌린 상태. .axe-workspace-disclosure[open] > summary 와 같은
 * 표현이되 재료는 세션 어휘의 것(--text-…/--bg-…)을 읽는다. */
.axe-session-head__new[open] > summary {
  color: var(--text-primary);
  background: var(--bg-subtle);
}

/* 여닫힘은 **author 가 정본으로 말한다**. 닫힌 <details> 의 자식을 감추는 것은
 * UA 스타일시트인데, UA origin 은 author origin 에 진다 — 패널에 display:flex 를
 * 무조건 주면 그 UA 규칙을 뚫어, 엔진에 따라 닫힌 채로 팝오버가 떠 있는다.
 * (감춤 수단이 엔진마다 다른 것도 이유다: 근래 엔진은 content-visibility 로,
 * 예전 엔진은 slot 의 display 로 감춘다 — 어느 쪽에 기대도 한쪽이 깨진다.)
 * 그래서 닫힘은 display:none 으로 명시하고, 상자는 [open] 에서만 세운다. */
.axe-session-head__new > .axe-session-head__new-panel {
  display: none;
}

.axe-session-head__new[open] > .axe-session-head__new-panel {
  position: absolute;
  z-index: var(--z-overlay, 400);
  top: calc(100% + var(--space-1));
  right: 0;
  width: 240px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-lg);
}

.axe-session-list {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* --compact = 레일용 한 줄 행. 32px 는 컨텍스트 레일의 위치 링크
 * (.axe-workspace-context__link)와 같은 리듬이라, 세션 목록이 그 위아래 어디에
 * 서도 같은 눈금 위에 앉는다. 기본 44px 두 줄은 작업면 목록이 계속 쓴다 —
 * 거기서는 메타를 접을 이유가 없다. 한 줄 행은 __meta 를 아예 내지 않고
 * (숨기는 것이 아니라 만들지 않는다) 메타를 __link 의 title 로 옮긴다.
 *
 * 이 32px 은 modifier 의 기본값이고, 컨텍스트 레일 __body 안에 서면 좌측 내비의
 * 30px 리듬으로 다시 눌린다(아래 "레일 안 컴팩트 목록" 블록) — 셸 안에서는
 * 좌우 두 기둥이 같은 눈금을 쓰는 것이 먼저다.
 *
 * justify-content 를 여기서 **다시 세우는 이유**: base 규칙(.axe-session-item__link)
 * 은 세로 flex 라 `justify-content: center` 가 두 줄(__name·__meta)을 44px 상자
 * 한가운데에 세우는 세로 정렬이다. 이 규칙이 축을 row 로 뒤집는 순간 그 **같은
 * 선언이 수평 축으로 옮겨 붙는다** — 컴팩트 행의 자식은 __dot 과 __name 뿐이라
 * (메타를 아예 내지 않는다) 남는 폭이 좌우로 균등 분배되고, 이름 묶음이 행
 * 가운데로 밀려 목록이 가운데 정렬로 보인다(운영자 실측 지적, 0.38.3).
 *
 * 규칙 하나: **축을 뒤집는 쪽이 그 축의 정렬 책임도 진다.** base 의 center 는
 * 지우지 않는다 — 작업면의 기본(두 줄) 행이 실제로 그 세로 중앙 정렬을 쓴다.
 * 0.38.1 이 세운 레일 스코프 규칙(.axe-workspace-context__body …)은 높이·패딩만
 * 다시 잡고 justify-content 를 건드리지 않으므로 이 한 줄이 그 자리까지 덮는다. */
.axe-session-list--compact .axe-session-item__link {
  min-height: 32px;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
}

.axe-session-item {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-1);
  border-radius: var(--radius-md);
}

/* status 도트 — 빈 원이 기본값이고(완료·미지정), 채운 원이 "지금 돌고 있다"다.
 * 8px 상자에 1.5px 테두리라 두 상태가 16px 도 안 되는 자리에서 갈린다.
 *
 * 도트는 **색으로만** 말하므로 aria-hidden 이고, 같은 상태를 행의 __link 가
 * 글로도 들어야 한다(aria-label="… — 진행 중"). 색만 있는 표현은 색각 이상에서
 * 사라지고, SR 에는 처음부터 존재하지 않는다.
 *
 * inline-block 을 명시하는 이유: 이 도트는 목록 행(flex/grid 자식)뿐 아니라 상세
 * 페이지의 상태 한 줄(<p> 안의 글 흐름)에도 선다. 거기서는 <span> 이 기본값
 * inline 이라 width/height 가 통째로 무시돼 도트가 사라진다. flex·grid 문맥에서는
 * 자식이 어차피 블록화되므로 이 선언이 아무것도 바꾸지 않는다 — 즉 한 줄로 두
 * 자리를 다 얻는다(.axe-status-light__dot 과 같은 처방). vertical-align 은 인라인
 * 문맥에서만 쓰이며, 글줄 한가운데 앉혀 baseline 에 매달리지 않게 한다. */
.axe-session-item__dot {
  flex: 0 0 auto;
  display: inline-block;
  width: 8px;
  height: 8px;
  border: 1.5px solid var(--text-muted);
  border-radius: var(--radius-full);
  background: transparent;
  vertical-align: middle;
}

.axe-session-item__dot--active {
  border-color: var(--success);
  background: var(--success);
}

/* 완료 = 기본값과 같은 빈 원. 명시 클래스를 두는 이유는 소비자가 상태를 따져
 * 붙였다는 사실이 마크업에 남아야 하기 때문이다(누락과 구분되지 않으면 나중에
 * 매핑이 틀려도 아무도 모른다). */
.axe-session-item__dot--done {
  border-color: var(--text-muted);
  background: transparent;
}

.axe-session-item__dot--archived {
  border-color: var(--text-muted);
  background: var(--text-muted);
}

/* 현재 세션 = 배경 tint 하나. 레일의 entity/계정 팝업 행(.axe-workspace-picker__item
 * [aria-current])과 같은 표현이며, 그 자리와 같은 재료를 받는다(셸 안에서
 * --bg-subtle == --workspace-selected). */
.axe-session-item--active,
.axe-session-item__link[aria-current] {
  background: var(--bg-subtle);
}

.axe-session-item__link {
  min-width: 0;
  min-height: 44px;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border: 0;
  border-radius: inherit;
  background: transparent;
  color: var(--text-secondary);
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.axe-session-item__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* 도트가 붙은 기본(두 줄) 행 — 세로 flex 로는 도트가 이름 **위** 딴 줄에 선다.
 * 마크업 계약(__dot 이 __link 의 첫 자식)은 두 조판이 같아야 하므로 손대지 않고,
 * 조판만 grid 로 바꿔 첫 줄에 도트·이름을, 둘째 줄 전폭에 메타를 앉힌다.
 *
 * --compact 를 :not() 으로 잘라내 두 규칙이 **애초에 같은 요소에 걸리지 않게**
 * 한다 — 특정도나 선언 순서로 다투게 두면 나중에 한쪽을 옮기는 순간 조용히
 * 뒤집힌다(한 줄 행은 이미 자기 규칙이 row flex 로 세운다).
 *
 * :has() 미지원 구형 브라우저는 기존 동작(도트가 딴 줄)으로 남는다 — 읽히기는
 * 하므로 점진 향상으로 수용한다. */
.axe-session-list:not(.axe-session-list--compact)
  .axe-session-item__link:has(> .axe-session-item__dot) {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--space-2);
  row-gap: var(--space-1);
  align-items: center;
}

.axe-session-list:not(.axe-session-list--compact)
  .axe-session-item__link:has(> .axe-session-item__dot)
  > .axe-session-item__meta {
  grid-column: 1 / -1;
}

/* 이름은 한 줄로 자른다 — 레일에서 두 줄로 흐르면 목록의 리듬이 무너지고,
 * 전문은 어차피 세션 페이지 헤더에 있다. */
.axe-session-item__name {
  min-width: 0;
  overflow: hidden;
  color: var(--text-primary);
  font-size: var(--text-sm);
  line-height: 1.4;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* 메타도 한 줄. 안에 배지가 들어와도 같은 줄에 서도록 flex 이며, 넘치는 만큼은
 * 잘린다(항목마다 말줄임 위치를 다르게 협상하지 않는다). */
.axe-session-item__meta {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  overflow: hidden;
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  line-height: 1.4;
  white-space: nowrap;
}

.axe-session-item__actions {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding-inline-end: var(--space-2);
}

/* 한 줄 행의 액션은 28px 리듬에 맞춘다. 규약 4 대로 버튼 재료는 소비자가
 * 조립하는데, 손에 잡히는 것(.axe-workspace-bar__icon-button)이 44×44 라 32px
 * 행에 그대로 들어오면 행 높이가 버튼에 끌려 올라간다.
 *
 * 캡은 **높이에만** 건다. 실제 행 액션은 아이콘이 아니라 글자인 경우가 많고
 * ("이름"·"복사"·"복사됨") 폭을 28px 로 못 박으면 그 라벨이 잘리기 때문이다.
 * 대신 폭은 auto 로 되돌리고 28px 바닥만 깐다 — 아이콘 재료는 그 바닥에 걸려
 * 28px 정사각(머리 버튼과 같은 상자)이 되고, 글자 재료는 제 폭대로 선다.
 *
 * width/flex 를 굳이 auto 로 되돌려 적는 이유: 아이콘 재료가 width:44px 와
 * flex:0 0 44px 를 들고 있어 가만두면 44px 폭이 남는데, __actions 는 opacity 로만
 * 숨으므로 그 폭은 **항상** 자리를 차지해 모든 세션 이름을 그만큼 일찍 자른다.
 * 이 규칙이 이긴다 — (0,2,1) 대 (0,1,0) 이고 이 파일에는 @layer 도 !important 도
 * 없다(값이 명시냐 auto 냐가 아니라 특정도가 정한다).
 *
 * 액션 자리를 **두 모양**으로 적는 이유: 계약이 <details><summary> 액션도 허용해
 * (이름변경 폼도 머리의 생성 폼과 같은 JS-0 수단을 쓴다) 직계 :is(a, button) 만
 * 잡으면 그 summary 가 44px 로 남는다. 그렇다고 자손 전체로 넓히면 반대편으로
 * 넘어간다 — 그 <details> 가 여는 패널 **안의** 제출 버튼(.axe-btn)까지 28px 로
 * 짓눌러 폼을 깨뜨린다. 그래서 계약이 허용하는 두 자리(직계 액션, 직계
 * <details> 의 summary)만 이름으로 집는다. */
.axe-session-list--compact .axe-session-item__actions > :is(a, button),
.axe-session-list--compact .axe-session-item__actions > details > summary {
  width: auto;
  min-width: 28px;
  height: 28px;
  min-height: 28px;
  flex: 0 0 auto;
  padding-block: 0;
}

/* details 컨테이너도 행 리듬에 세운다 — 머리의 __new 와 같은 상자(inline-flex)라
 * summary 하나만 담긴 28px 로 서고, 패널은 그 위에 띄운다. */
.axe-session-list--compact .axe-session-item__actions > details {
  display: inline-flex;
}

/* 끝난 행의 이름은 물러난다 — 압축 목록(레일) 한정, 이름만 55% (0.38.9).
 *
 * 레일의 세션 목록은 "지금 무엇이 돌고 있나" 를 먼저 말해야 하는데, 완료·보관 행이
 * 진행 중 행과 **같은 밝기**로 서면 그 질문의 답이 목록 전체에 흩어진다. 도트가
 * 이미 상태를 지지만 8px 원 하나는 행 스캔에서 이름보다 늦게 읽힌다 — 눈이 먼저
 * 잡는 것은 글자 덩어리다. 그래서 **글자 쪽에서** 한 단계 물러나게 한다.
 *
 * 물러나는 것은 **이름뿐이고 점은 불변**이다. 상태의 정본은 도트와 aria-label 이고
 * (규약 5), 흐림은 그 위에 얹는 보조 신호다 — 순서를 뒤집어 흐림이 상태를 지게
 * 하면 그 순간 상태가 다시 "색·명도로만 말하는 표현" 이 되어 규약 5 가 세운 짝이
 * 무너진다. 도트를 같이 흐리지 않는 것도 같은 이유다: 정본은 밝기를 잃지 않는다.
 *
 * 55% 인 이유(운영자 승인 픽스처 B): 레일 resting 이름은 이미 --text-secondary
 * (= --workspace-muted)로 눕혀 있어, 여기서 더 낮추면 읽히는 대비가 아니라 "사라진
 * 행" 이 된다. 55% 는 진행 중 행과 나란히 놓았을 때 **한 눈에 갈리되 이름은 그대로
 * 읽히는** 자리다. 흐림은 대비를 낮추므로 **완료·보관에만** 건다 — 진행 중 행이
 * 이 규칙에 걸리지 않는 것이 이 처방의 안전판이다.
 *
 * **압축 목록 한정**인 이유: 기본(두 줄) 행은 __meta 가 서고 그 안의 가시 배지가
 * 상태를 이미 글로 진다(규약 5). 거기서 이름을 또 흐리면 같은 말을 두 번 하면서
 * 대비만 잃는다. 흐림은 **배지가 설 자리가 없는 조판의 대타**다.
 *
 * `:has(> …)` 로 도트를 직계 자식으로 요구하는 것은 계약 그대로다(규약 5 — 도트는
 * __link 의 첫 자식). :has() 미지원 브라우저는 흐림 없이 남는다 — 상태는 도트와
 * aria-label 이 이미 지고 있으므로 잃는 것이 없는 점진 향상이다.
 *
 * 특정도: (0,4,0) — --compact + __link + :has() 인자(그 안에서 가장 특정한 것
 * (0,1,0)) + __name. 아래 복귀 규칙들은 이 값을 넘기거나(hover·focus·현재 행)
 * 같은 값에 뒤 순서로 이긴다(reduced-motion·forced-colors). */
.axe-session-list--compact
  .axe-session-item__link:has(
    > :is(.axe-session-item__dot--done, .axe-session-item__dot--archived)
  )
  .axe-session-item__name {
  opacity: 0.55;
  transition: opacity var(--duration-fast) var(--ease-out);
}

/* 손·키보드·현재 위치에서는 원래 밝기로 돌아온다. 흐림은 "덜 중요하다" 는 말이지
 * "지금 만지고 있는 것도 덜 중요하다" 는 말이 아니다 — 상호작용 중인 행이 물러난
 * 채로 있으면 그 행이 응답하지 않는 것처럼 읽힌다.
 *
 * `[aria-current]` 와 `--active` 를 **둘 다** 집는 이유는 계약이 두 표기를 다
 * 허용하기 때문이다(규약 2 — 시각만 바꾸는 --active 를 붙인 소비자도 같은 그림을
 * 받아야 한다). 위 레일 색 규칙(0.38.4)이 같은 두 갈래를 집는 것과 같은 처방이다.
 * 완료된 세션을 **열어 둔** 상태가 실재하므로(끝난 세션도 읽는다) 이 복귀는 이론이
 * 아니라 매일 걸리는 갈래다.
 *
 * hover 는 여기 없다 — 포인터가 있는 환경에서만 성립하므로 아래
 * `@media (hover: hover) and (pointer: fine)` 블록 안에 선다. 터치에서 hover 는
 * 오지 않거나 탭 후 남아, 여기 두면 만진 행이 흐림에서 영구히 빠져나온다. */
.axe-session-list--compact
  :is(
    .axe-session-item--active > .axe-session-item__link,
    .axe-session-item__link:is(:focus-visible, [aria-current])
  ):has(> :is(.axe-session-item__dot--done, .axe-session-item__dot--archived))
  .axe-session-item__name {
  opacity: 1;
}

/* 레일 안 컴팩트 목록은 좌측 내비(.axe-workspace-rail__link)의 행 리듬을 그대로
 * 잇는다 — 같은 인셋(8px) · 행높이(30px) · radius(8px) · 행간(1px) · resting
 * 색(muted 로 눕고 hover·현재 행에서만 밝아진다). 두 레일은 같은 셸의 좌우
 * 기둥이라, 한쪽만 다른 눈금을 쓰면 그 차이가 곧 소음이다.
 *
 * __body 의 16px 패딩을 목록만 -8px 되물려 hover pill 이 좌측 __nav 와 같은 8px
 * 인셋에 선다. 되무는 것이 목록뿐이라 머리(.axe-session-head)의 제목은 __body
 * 패딩 자리에 그대로 남고, 행의 8px 안쪽 패딩이 제목과 이름의 x 를 다시 맞춘다
 * (둘 다 레일 가장자리에서 16px) — pill 만 더 나오고 글줄은 어긋나지 않는다.
 * 좌측이 pill 을 세우는 그림과 같다.
 *
 * 스코프가 **두 벌**인 이유(0.38.4): 이 정렬은 "좌측 레일과 물리적으로 같은 셸에
 * 섰을 때" 의 계약인데, 슬롯 ⓪ 이 계약상 두 자리에 설 수 있어 그 자리도 둘이다.
 *   · `.axe-workspace-context …` = 패널 **안** 어디서나 (첫-자식 갈래. gate 처럼
 *     `__body` 래퍼 없이 평평하게 선 세션 목록이 여기서 걸린다 — 0.38.3 까지는
 *     `__body` 스코프뿐이라 이 갈래가 32px·radius-md·상시 밝은 이름으로 남아
 *     좌측과 눈금이 갈렸다.)
 *   · `.axe-workspace-context__body …` = 패널 **밖**에서 이 클래스를 래퍼로 빌려
 *     쓴 앞-형제 갈래 (blueprint 가 그 자리다 — 패널 밖이라 위 선택자에 안 걸린다).
 * 두 선택자는 같은 선언을 들고 특정도도 같아, 겹쳐 걸리는 소비자(cortex·index)는
 * 결과가 바뀌지 않는다. 레일 **밖**(작업면 목록·팝오버)은 여전히 32px 기본값이다.
 *
 * 좌측 토큰(--workspace-nav-row-h · --workspace-nav-row-gap)을 직접 읽는 것은
 * 의도된 결합이다 — 좌측 리듬이 움직이면 이 목록이 따라간다. 폴백을 병기해 그
 * 토큰이 없는 문맥(셸 밖에서 __body 클래스만 빌려 쓰는 경우)에서도 값이 성립한다. */
.axe-workspace-context .axe-session-list--compact,
.axe-workspace-context__body .axe-session-list--compact {
  margin-inline: calc(var(--space-2) - var(--space-4));
  gap: var(--workspace-nav-row-gap, 1px);
}

.axe-workspace-context .axe-session-list--compact .axe-session-item,
.axe-workspace-context__body .axe-session-list--compact .axe-session-item {
  border-radius: 8px;
}

.axe-workspace-context .axe-session-list--compact .axe-session-item__link,
.axe-workspace-context__body .axe-session-list--compact .axe-session-item__link {
  min-height: var(--workspace-nav-row-h, 30px);
  padding: 3px var(--space-2);
}

/* 이름은 제 색을 들지 않고 링크의 색을 받는다 — 링크가 resting 에서
 * --text-secondary(셸 안에서 = --workspace-muted)라 목록이 좌측처럼 조용히 눕고,
 * hover 규칙이 링크를 --text-primary 로 올리면 이름도 같이 올라온다(inherit 은
 * 그때그때 부모의 계산값이라 상태 전환을 그대로 따른다). */
.axe-workspace-context .axe-session-list--compact .axe-session-item__name,
.axe-workspace-context__body .axe-session-list--compact .axe-session-item__name {
  color: inherit;
}

/* 현재 행은 좌측의 [aria-current="page"] 와 같이 tint **와** 밝은 글자를 함께
 * 받는다. 기존 규칙(.axe-session-item__link[aria-current])은 background 만 올리는데,
 * 위에서 __name 이 제 색을 놓았으므로 여기서 색까지 세우지 않으면 현재 행이
 * 이웃과 같은 muted 로 주저앉는다 — 좌측에서 현재 행이 유일하게 밝은 행인 것과
 * 정반대가 된다. --active(<li>) 갈래도 함께 집는 이유: 계약이 두 표기를 다
 * 허용하고, 시각만 바꾸는 --active 를 붙인 소비자도 같은 그림을 받아야 한다. */
.axe-workspace-context
  .axe-session-list--compact
  .axe-session-item--active
  > .axe-session-item__link,
.axe-workspace-context
  .axe-session-list--compact
  .axe-session-item__link[aria-current],
.axe-workspace-context__body
  .axe-session-list--compact
  .axe-session-item--active
  > .axe-session-item__link,
.axe-workspace-context__body
  .axe-session-list--compact
  .axe-session-item__link[aria-current] {
  color: var(--text-primary);
}

/* 액션은 마우스가 있는 환경에서만 숨는다. 숨기는 수단이 opacity 인 이유는 자리를
 * 미리 잡아 두기 위함이다 — display 로 접으면 hover 마다 이름 폭이 널뛴다.
 * 포인터가 없는 환경(터치·키보드 전용)에서는 hover 가 오지 않으므로 항상 보인다. */
@media (hover: hover) and (pointer: fine) {
  .axe-session-item__actions {
    opacity: 0;
    transition: opacity var(--duration-fast) var(--ease-out);
  }

  .axe-session-item:hover .axe-session-item__actions,
  .axe-session-item:focus-within .axe-session-item__actions {
    opacity: 1;
  }

  .axe-session-item__link:not([aria-current]):hover {
    background: var(--bg-subtle);
    color: var(--text-primary);
    text-decoration: none;
  }

  /* 완료·보관 행의 흐림도 hover 에서 걷힌다(0.38.9). 위 규칙이 링크를
   * --text-primary 로 올리는데 이름만 55% 로 남으면, 만지고 있는 행 하나가 색은
   * 밝고 글자는 물러난 어중간한 상태로 선다. 이 블록 안에 두는 이유는 hover 가
   * 포인터 환경의 신호이기 때문이다 — 터치에서는 탭 뒤 hover 가 눌어붙어, 밖에
   * 두면 한 번 만진 행이 흐림에서 영구히 빠진다.
   *
   * 특정도 (0,5,0) — 흐림 규칙(0,4,0)을 값으로 이긴다(미디어 질의는 특정도를
   * 더하지 않으므로 순서에 기대지 않는다). */
  .axe-session-list--compact
    .axe-session-item__link:hover:has(
      > :is(.axe-session-item__dot--done, .axe-session-item__dot--archived)
    )
    .axe-session-item__name {
    opacity: 1;
  }

  /* 머리 아이콘은 액션과 달리 항상 보인다 — 숨을 것이 없으므로 hover 는 재료만
   * 올린다(열린 <details> 의 눌린 상태와 같은 tint). 비활성에는 걸지 않는다:
   * 누를 수 없는 것이 hover 에 반응하면 그것이 곧 거짓 affordance 다
   * (.axe-btn 계열과 같은 :not(:disabled) 가드 + aria-disabled 표기까지). */
  .axe-session-head__button:hover:not(:disabled):not([aria-disabled="true"]) {
    color: var(--text-primary);
    background: var(--bg-subtle);
  }
}

.axe-session-post {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
}

/* 머리는 감싼다 — origin 라벨이 "claude-code@어떤-호스트" 처럼 길어질 수 있고,
 * 그때 시각을 밀어내는 것보다 줄을 하나 더 쓰는 편이 읽힌다. */
.axe-session-post__head {
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.axe-session-post__author {
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.axe-session-post__origin {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

/* 시각은 머리 오른쪽 끝. margin auto 라 origin 이 없어도 자리가 흔들리지 않는다. */
.axe-session-post__time {
  flex: 0 0 auto;
  margin-inline-start: auto;
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* 본문은 조판을 스스로 정하지 않는다 — 마크다운이면 .axe-prose 를 함께 붙이고,
 * 여기서는 붙여넣은 전사(轉寫)가 카드를 가로로 밀어내지 않게만 막는다. */
.axe-session-post__body {
  min-width: 0;
  color: var(--text-primary);
  font-size: var(--text-sm);
  line-height: var(--leading-body);
  overflow-wrap: anywhere;
}

/* 마크다운 렌더러가 없는 소비자용 — 원문을 이스케이프해 그대로 세운다. pre-wrap
 * 이라 개행이 살고, 카드를 가로로 밀어내지 않는 일은 위의 __body 가 이미 한다.
 * 태그는 <pre> 를 권장한다 — 복사할 때 개행이 그대로 따라간다. */
.axe-session-post__body--plain {
  white-space: pre-wrap;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.6;
}

@media (hover: hover) and (pointer: fine) {
  .axe-workspace-bar__routes a:not([aria-current="page"]):hover,
  .axe-workspace-bar__icon-button:hover,
  .axe-workspace-disclosure > summary:hover,
  .axe-workspace-entity > summary:hover,
  .axe-workspace-rail__group-label:is(a, button):hover,
  .axe-workspace-rail__link:is(a, button):not([aria-current="page"]):hover,
  .axe-workspace-rail__nav
    .axe-sidebar__item:not(.axe-sidebar__item--active)
    > .axe-sidebar__link:hover,
  .axe-workspace-rail__nav .axe-sidebar__group-header:hover,
  .axe-workspace-search:hover,
  .axe-workspace-entity:is(a, button):hover,
  .axe-workspace-identity:is(a, button, summary):hover,
  .axe-workspace-picker__item:not([aria-current]):hover,
  .axe-workspace-picker__close:hover,
  .axe-prompt-card__copy:not([aria-disabled="true"]):hover,
  .axe-workspace-context__link:hover {
    color: var(--workspace-text);
    background: var(--workspace-selected);
    text-decoration: none;
  }
}

/* 팝업은 접힌 폭의 표면이지만 계약은 폭을 가리지 않는다 — 넓은 화면에서 열리면
 * 화면 가운데에 선다(아래 붙임은 엄지 거리 때문이지 규칙이 아니다). */
@media (min-width: 640px) {
  .axe-workspace-picker-dialog {
    align-items: center;
  }
}

/* AppShell geometry --------------------------------------------------- */

@media (min-width: 1024px) {
  .axe-app-shell.axe-workspace-shell[data-shell="docs"] .axe-app-shell__main {
    grid-template-columns: var(--workspace-rail-w) minmax(0, 1fr);
  }

  .axe-workspace-shell .axe-app-shell__sidebar {
    top: 0;
    height: 100vh;
    height: 100dvh;
    max-height: 100vh;
    max-height: 100dvh;
    margin-top: calc(-1 * var(--workspace-topbar-h));
    z-index: calc(var(--z-sticky, 100) + 1);
    overflow-y: hidden;
  }

  .axe-workspace-bar {
    grid-template-columns: var(--workspace-rail-w) minmax(0, 1fr) auto;
    border-bottom: 0;
  }

  .axe-workspace-bar__left {
    padding-inline: var(--space-4);
    background: var(--workspace-rail);
    border-right: 1px solid var(--workspace-border);
  }

  .axe-workspace-bar__center,
  .axe-workspace-bar__right {
    background: var(--workspace-canvas);
    border-bottom: 1px solid var(--workspace-border);
  }

  .axe-workspace-bar__right {
    padding-inline: var(--space-4);
  }

  .axe-workspace-bar__routes {
    display: flex;
  }

  .axe-workspace-bar__mobile-brand,
  .axe-workspace-disclosure--navigation,
  .axe-workspace-bar__right > .axe-workspace-search {
    display: none;
  }

  /*
   * 접기 (opt-in) ------------------------------------------------------
   * 상태는 셸 루트의 boolean 속성 `data-rail-collapsed` 하나다 — 있으면 접힘,
   * 없으면 펼침. `="false"` 같은 값으로 끄지 못한다(속성 존재가 곧 상태다).
   * 속성이 없는 셸은 아래 어느 selector 와도 매칭되지 않으므로 종전 기하가
   * 바이트 단위로 유지된다. 토글 버튼을 렌더하지 않는 표면은 이 속성을 쓸
   * 일이 없다 = 접히지 않는 표면(계약상 opt-in 의 뜻).
   *
   * 접힘은 데스크톱에서만 의미가 있다. ≤1023px 에서는 레일이 이미 서랍의
   * 것이라 이 블록 밖에는 대응 규칙을 두지 않는다 — 속성이 남아 있어도 무해.
   *
   * 토글 인스턴스는 둘이고 상태마다 정확히 하나만 보인다. 펼침 = 레일 brand 행의
   * 것(레일과 함께 사라진다), 접힘 = bar 좌측 칸의 것(그때야 그 자리가 비어 눌린다).
   */
  .axe-workspace-rail__brand .axe-workspace-rail-toggle {
    display: inline-flex;
  }

  .axe-workspace-shell[data-rail-collapsed] .axe-workspace-bar .axe-workspace-rail-toggle {
    display: inline-flex;
  }

  .axe-app-shell.axe-workspace-shell[data-rail-collapsed] .axe-app-shell__sidebar {
    display: none;
  }

  /* 사이드바 트랙을 뺀 대응 규칙 — 펼침 규칙과 1:1. */
  .axe-app-shell.axe-workspace-shell[data-rail-collapsed][data-shell="docs"] .axe-app-shell__main,
  .axe-app-shell.axe-workspace-shell[data-rail-collapsed][data-shell="dashboard"] .axe-app-shell__main {
    grid-template-columns: minmax(0, 1fr);
  }

  /* context rail 은 3번 트랙을 명시로 잡고 있다 — 첫 트랙이 사라졌으니 함께
   * 당겨야 한다. 안 당기면 없는 트랙이 암묵 생성돼 본문 오른쪽에 빈 칸이 남는다. */
  .axe-app-shell.axe-workspace-shell[data-rail-collapsed] .axe-app-shell__toc {
    grid-column: 2;
  }

  .axe-workspace-shell[data-rail-collapsed] .axe-workspace-bar {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }

  /* 좌측 zone 은 레일의 머리였다 — 레일이 없으면 그 색도 없다. canvas 로
   * 돌리고 아래 경계선을 이어 bar 가 한 줄로 읽히게 한다(1024–1439 구간의
   * 우측 zone 처리와 같은 원리). */
  .axe-workspace-shell[data-rail-collapsed] .axe-workspace-bar__left {
    background: var(--workspace-canvas);
    border-right: 0;
    border-bottom: 1px solid var(--workspace-border);
  }
}

@media (min-width: 1440px) {
  .axe-app-shell.axe-workspace-shell[data-shell="docs"] .axe-app-shell__main {
    grid-template-columns:
      var(--workspace-rail-w)
      minmax(0, 1fr)
      var(--workspace-context-w);
  }

  .axe-workspace-bar {
    grid-template-columns:
      var(--workspace-rail-w)
      minmax(0, 1fr)
      var(--workspace-context-w);
  }

  .axe-workspace-bar__right {
    background: var(--workspace-rail);
    border-bottom: 0;
    border-left: 1px solid var(--workspace-border);
  }

  .axe-workspace-disclosure--context {
    display: none;
  }

  /*
   * 2-zone (context rail 없음) — bar 는 반드시 __main 과 같은 zone 수를 가져야
   * 한다. 위 .axe-workspace-bar 규칙은 무조건 3-zone(rail|1fr|rail)로 넓히지만,
   * data-has-toc="false" 인 셸의 __main 은 layout.css 의 (0,5,0) 규칙이 잡아
   * 2-zone(rail|1fr)로 남는다. 그 불일치가 우측 상단에 아래가 비어 있는
   * rail 색 블록을 만든다 (cortex 2-zone 채택에서 발견, D-ui-9 phase-3).
   *
   * 셸이 이미 노출하는 같은 신호(data-has-toc, AppShell.tsx 가 내보내고
   * maud/jinja 소비자가 그대로 쓰는 계약)로 키잉 — 새 클래스명 없음.
   * 결과는 1024–1439 구간 처리와 동일: 우측 zone 은 내용폭(auto)이고
   * canvas 위에 얹혀 bar 하단 경계선을 잇는다.
   *
   * 3-zone DOM 은 data-has-toc="true" 라 이 두 selector 와 매칭 불가 —
   * design.axelabs.ai · gate 기하는 원리적으로 무변화.
   */
  .axe-workspace-shell[data-has-toc="false"] .axe-workspace-bar {
    grid-template-columns: var(--workspace-rail-w) minmax(0, 1fr) auto;
  }

  .axe-workspace-shell[data-has-toc="false"] .axe-workspace-bar__right {
    background: var(--workspace-canvas);
    border-bottom: 1px solid var(--workspace-border);
    border-left: 0;
  }

  /* 접힘 3-zone — 좌측 트랙만 빠지고 context rail 은 남는다. */
  .axe-app-shell.axe-workspace-shell[data-rail-collapsed][data-shell="docs"] .axe-app-shell__main {
    grid-template-columns: minmax(0, 1fr) var(--workspace-context-w);
  }

  .axe-workspace-shell[data-rail-collapsed] .axe-workspace-bar {
    grid-template-columns: auto minmax(0, 1fr) var(--workspace-context-w);
  }

  /* 2-zone 셸(context rail 없음)은 접히면 1-zone 이 된다 — 펼침 상태에서
   * layout.css 의 (0,5,0) 규칙이 하던 몫을 접힘 쪽에서도 같은 신호로 잡는다. */
  .axe-app-shell.axe-workspace-shell[data-rail-collapsed][data-shell="docs"][data-has-toc="false"] .axe-app-shell__main {
    grid-template-columns: minmax(0, 1fr);
  }

  .axe-workspace-shell[data-rail-collapsed][data-has-toc="false"] .axe-workspace-bar {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }
}

@media screen and (min-width: 1024px) and (max-width: 1439.98px) {
  .axe-workspace-shell .axe-app-shell__toc {
    display: none;
  }
}

@media (max-width: 1023.98px) {
  .axe-app-shell.axe-workspace-shell[data-shell="docs"] .axe-app-shell__main {
    grid-template-columns: minmax(0, 1fr);
  }

  .axe-workspace-shell :is(.axe-app-shell__sidebar, .axe-app-shell__toc) {
    display: none;
  }

  .axe-workspace-shell .axe-app-shell__subnav {
    display: block;
    background: var(--workspace-rail);
    border-color: var(--workspace-border);
  }

  .axe-workspace-shell .axe-app-shell__subnav-summary {
    color: var(--workspace-text);
    background: var(--workspace-rail);
  }

  .axe-workspace-shell .axe-app-shell__subnav-panel {
    max-height: calc(100dvh - var(--workspace-topbar-h) - var(--app-shell-subnav-h));
    overflow-y: auto;
    background: var(--workspace-rail);
    border-color: var(--workspace-border);
  }
}

/* 손가락에는 눈금보다 손끝이 먼저다 — 포인터가 굵으면 셸의 조밀한 행들이 모두
 * 44px 로 열린다. 세션 행도 같이 열어야 좌우 두 기둥이 터치에서도 같은 높이로
 * 선다(좌측 .axe-workspace-rail__link 가 여기서 30px → 44px 로 가는데 우측만
 * 30px 로 남으면, 정렬해 둔 리듬이 정작 손으로 만지는 자리에서 도로 갈린다).
 *
 * **이 블록은 자기가 여는 행들의 규칙보다 뒤에 있어야 한다.** 여기 선택자는
 * 원 규칙과 특정도가 같고(미디어 질의는 특정도를 더하지 않는다) 순서로만 이긴다
 * — 좌측 __link 가 이미 그렇게 서 있고 세션 행도 같은 방식으로 얹는다. 블록을
 * 위로 옮기면 두 리듬이 조용히 원래 높이로 돌아간다. */
@media (pointer: coarse) {
  .axe-workspace-bar__routes a,
  .axe-workspace-rail__group-label,
  .axe-workspace-rail__link,
  .axe-workspace-rail__nav :is(.axe-sidebar__group-header, .axe-sidebar__link),
  .axe-workspace-search,
  .axe-workspace-entity:is(a, button),
  .axe-workspace-entity > summary,
  .axe-workspace-context__link,
  .axe-workspace-context .axe-session-list--compact .axe-session-item__link,
  .axe-workspace-context__body .axe-session-list--compact .axe-session-item__link {
    min-height: 44px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .axe-workspace-entity:is(a, button),
  .axe-workspace-entity:is(a, button) > svg,
  .axe-workspace-entity:is(a, button)::after,
  .axe-workspace-entity > summary,
  .axe-workspace-entity > summary > svg,
  .axe-workspace-entity > summary::after,
  .axe-workspace-identity,
  .axe-workspace-identity--entity > svg,
  .axe-workspace-identity-menu > summary::after,
  .axe-workspace-identity-menu__panel,
  .axe-workspace-bar__routes a,
  .axe-workspace-rail__group-label,
  .axe-workspace-rail__link,
  .axe-workspace-rail__nav :is(.axe-sidebar__group-header, .axe-sidebar__link),
  .axe-workspace-search {
    transition: none;
  }

  /* 완료·보관 행 이름의 흐림은 **남고 전환만 사라진다**(0.38.9) — reduced-motion
   * 은 움직임을 줄이라는 요청이지 상태 표현을 지우라는 요청이 아니다. 선택자를
   * 그대로 반복하는 이유는 특정도다: 흐림 규칙이 (0,4,0) 이라 위 목록의
   * (0,1,0) 짜리 이름들 옆에 얹으면 transition 이 지워지지 않는다. 같은 값에
   * 이 블록이 뒤에 있어 순서로 이긴다. */
  .axe-session-list--compact
    .axe-session-item__link:has(
      > :is(.axe-session-item__dot--done, .axe-session-item__dot--archived)
    )
    .axe-session-item__name {
    transition: none;
  }

  details.axe-workspace-identity-menu > .axe-workspace-identity-menu__panel {
    animation: none;
  }
}

@media (forced-colors: active) {
  .axe-workspace-bar__routes a[aria-current="page"],
  .axe-workspace-rail__link[aria-current="page"],
  .axe-workspace-rail__nav .axe-sidebar__item--active > .axe-sidebar__link {
    outline: 1px solid CanvasText;
    outline-offset: -1px;
  }

  .axe-workspace-context__tab[aria-current="page"],
  .axe-workspace-context__tab[aria-selected="true"],
  .axe-workspace-context__tab[data-state="active"] {
    border-bottom: 2px solid CanvasText;
  }

  /* status 도트 — 강제색 모드는 author 색을 시스템 색으로 갈아끼우므로, 두면
   * --active(초록 채움)와 --done(빈 원)이 같은 색으로 수렴해 구분이 사라진다.
   * 여기서 지켜야 할 것은 색이 아니라 **채움 대 빈 원**이라는 형태 대비다:
   * 진행 중은 본문색으로 채우고, 완료는 바탕색으로 비워 테두리만 남기며,
   * 보관은 흐린 색으로 채워 셋이 서로 갈린다.
   *
   * 시스템 키워드로 적는 것만으로는 부족하다 — 기본값 forced-color-adjust: auto
   * 에서는 UA 가 **이미 시스템 색인 선언까지** 다시 매핑하므로, 채움과 테두리가
   * 같은 쌍으로 뭉개져 방금 만든 형태 대비가 도로 사라질 수 있다. none 으로
   * 이 요소만 재치환에서 빼 위 값들을 적은 대로 쓴다.
   *
   * 보통 none 은 사용자가 거부한 색을 되살릴 위험 때문에 함부로 쓰지 않지만,
   * 여기서는 지키는 값 자체가 시스템 키워드(CanvasText·GrayText·Canvas)라
   * 사용자의 팔레트를 그대로 따른다 — 브랜드 색은 한 방울도 돌아오지 않는다. */
  .axe-session-item__dot {
    forced-color-adjust: none;
  }

  .axe-session-item__dot--active {
    border-color: CanvasText;
    background: CanvasText;
  }

  .axe-session-item__dot--done {
    border-color: GrayText;
    background: Canvas;
  }

  .axe-session-item__dot--archived {
    border-color: GrayText;
    background: GrayText;
  }

  /* 완료·보관 행 이름의 흐림은 **걸지 않는다**(0.38.9). 강제색 모드에는 명도 축이
   * 없다 — 사용자가 고른 두세 가지 시스템 색만 남으므로, opacity 로 낮춘 글자는
   * "한 단계 물러난 글자" 가 아니라 바탕에 섞여 **사라지는 글자**가 된다(그 팔레트가
   * 흔히 검정 바탕에 흰 글자라 55% 는 회색이 아니라 소실이다). 여기서 상태를 지는
   * 것은 이 모드가 형태 대비로 다시 세운 위 도트들과 __link 의 aria-label 이고,
   * 흐림은 애초에 그 위에 얹은 보조 신호이므로 빼도 잃는 정보가 없다.
   *
   * 선택자를 그대로 반복해 같은 (0,4,0) 으로 맞추고 뒤 순서로 이긴다 — forced-colors
   * 는 author 의 색만 갈아끼울 뿐 opacity 는 건드리지 않으므로, 여기서 되돌리지
   * 않으면 흐림이 그대로 살아 남는다. */
  .axe-session-list--compact
    .axe-session-item__link:has(
      > :is(.axe-session-item__dot--done, .axe-session-item__dot--archived)
    )
    .axe-session-item__name {
    opacity: 1;
  }
}

/* source: styles/indicators.css */
/* ============================================================
 * Indicators (Phase 4) — Skeleton / Spinner / Avatar / Progress
 *
 *   본 파일은 components.css 에 통합되기 전 Phase 4 격리 CSS.
 *   소비자는 globals.css 또는 showcase page 에서 직접 import.
 *
 *   모든 애니메이션 prefers-reduced-motion: reduce 존중.
 *   CSS-only — JS 의존 0.  성능 budget < 1KB gz / 컴포넌트.
 * ============================================================ */

/* ---------- sr-only (a11y 유틸; Spinner 가 의존) ---------- */
.axe-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
 * Skeleton — content placeholder.
 *   shimmer = ::after overlay 의 transform sweep — compositor-only
 *   (background-position 애니메이션은 paint-bound → transform 으로 통일).
 *   variant: text(line) / circle / rect(default).
 * ============================================================ */
.axe-skeleton {
  display: block;
  position: relative;
  overflow: hidden; /* radius clip — sweep 가 모서리 밖으로 안 새게. */
  background: var(--bg-subtle);
  border-radius: var(--radius-md);
}

.axe-skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in oklch, var(--text-primary) 6%, transparent),
    transparent
  );
  animation: axe-shimmer 1.4s var(--ease-in-out, ease-in-out) infinite;
}

.axe-skeleton--text {
  height: 1em;
  border-radius: var(--radius-sm);
  /* text line 은 1em 기본; 사용자가 height 로 덮어쓰면 그게 우선. */
}

.axe-skeleton--circle {
  border-radius: 9999px;
  aspect-ratio: 1 / 1;
}

.axe-skeleton--rect {
  /* rect 기본; 사용자가 width/height 명시. */
}

/* 공유 shimmer keyframes — dashboard.css (MetricCard/PipelineTable skel) 와
 * data-display.css (DataTable skel) 도 본 keyframes 를 사용.
 * components.css import 순서상 indicators 가 가장 먼저 로드됨. */
@keyframes axe-shimmer {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}

/* ============================================================
 * Spinner — indeterminate.
 *   svg + circle stroke-dasharray rotation.
 *   prefers-reduced-motion 시 dot 만 깜박임.
 * ============================================================ */
.axe-spinner {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  vertical-align: middle;
  color: var(--accent);
  line-height: 1;
}

.axe-spinner__svg {
  display: block;
  animation: axe-spinner-rotate 0.9s linear infinite;
}

.axe-spinner__track {
  stroke: color-mix(in oklch, currentColor 18%, transparent);
}

.axe-spinner__head {
  stroke: currentColor;
  /* circumference = 2 * PI * 10 ≈ 62.83.  1/4 가시 (15.7), 3/4 갭. */
  stroke-dasharray: 15.7 62.83;
  transform-origin: center;
}

/* reduced-motion 대체: dot pulse */
.axe-spinner__dot {
  display: none;
  width: 0.5em;
  height: 0.5em;
  border-radius: 9999px;
  background: currentColor;
}

.axe-spinner__label {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

@keyframes axe-spinner-rotate {
  to { transform: rotate(360deg); }
}

@keyframes axe-spinner-pulse {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .axe-spinner__svg { display: none; }
  .axe-spinner__dot {
    display: inline-block;
    animation: axe-spinner-pulse 1.4s ease-in-out infinite;
  }
}

/* ============================================================
 * Avatar — Radix Avatar 위 styling.
 *   size sm 24 / md 32 / lg 48.  fallback initials 자동 layout.
 * ============================================================ */
.axe-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 9999px;
  background: var(--bg-subtle);
  color: var(--text-secondary);
  font-family: var(--font-display, inherit);
  font-weight: var(--weight-medium);
  user-select: none;
  vertical-align: middle;
  flex-shrink: 0;
}

.axe-avatar--sm { width: 24px; height: 24px; font-size: 10px; }
.axe-avatar--md { width: 32px; height: 32px; font-size: 12px; }
.axe-avatar--lg { width: 48px; height: 48px; font-size: 18px; }

.axe-avatar__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

.axe-avatar__fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
  background: var(--bg-subtle);
}

/* ============================================================
 * Progress — Radix Progress 위 styling.
 *   determinate: transform translateX 로 indicator 이동.
 *   indeterminate: sweep keyframes.
 *   variant: default(accent) / success / danger.
 * ============================================================ */
.axe-progress {
  position: relative;
  overflow: hidden;
  width: 100%;
  height: 6px;
  background: var(--bg-subtle);
  border-radius: 9999px;
  /* Radix 가 max/value 를 aria 로 설정 — 추가 처리 불필요. */
  /* iOS Safari 의 transform overflow bug 방어. */
  transform: translateZ(0);
}

.axe-progress__indicator {
  width: 100%;
  height: 100%;
  background: var(--accent);
  border-radius: inherit;
  transition: transform var(--duration-base, 200ms) var(--ease-out, ease-out);
}

.axe-progress--success .axe-progress__indicator { background: var(--success); }
.axe-progress--danger  .axe-progress__indicator { background: var(--danger); }

/* Indeterminate — indicator 를 1/3 폭의 sweep 으로 변환. */
.axe-progress--indeterminate .axe-progress__indicator {
  width: 33%;
  transform: translateX(-100%);
  animation: axe-progress-sweep 1.4s ease-in-out infinite;
  transition: none;
}

@keyframes axe-progress-sweep {
  0%   { transform: translateX(-100%); }
  50%  { transform: translateX(150%); }
  100% { transform: translateX(300%); }
}

@media (prefers-reduced-motion: reduce) {
  .axe-skeleton::after {
    content: none;
  }
  .axe-progress__indicator {
    transition: none;
  }
  .axe-progress--indeterminate .axe-progress__indicator {
    animation: none;
    width: 100%;
    transform: translateX(0);
    opacity: 0.6;
  }
}

/* source: styles/dashboard.css */
/* ============================================================
 * Dashboard primitives (Phase 7)
 *   StatusLight · MetricCard · PipelineTable
 *
 *   본 파일은 components.css 통합 전 Phase 7 격리 CSS.  소비자는
 *   globals.css 또는 showcase page 에서 직접 import.
 *
 *   원칙
 *     · token-only — Tailwind 0, hard-coded color 0.
 *     · CSS-only animation (pulse / hover transition).
 *     · prefers-reduced-motion: reduce 시 모든 motion 정지/완화.
 *     · light/dark 자동 — CSS var 만 사용.
 * ============================================================ */

/* ============================================================
 * StatusLight — 색 dot (+ optional label / timestamp).
 *
 *   variant canonical: ok | warning | danger | muted | running
 *     ok      → --success
 *     warning → --warning
 *     danger  → --danger
 *     muted   → --text-muted (회색)
 *     running → --info       (파란 계열, pulse 권장)
 *
 *   size sm 8 / md 10 / lg 12 (px).  baseline 정렬은 inline-flex.
 * ============================================================ */
.axe-status-light {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  line-height: 1;
  vertical-align: middle;
}

.axe-status-light__dot {
  flex-shrink: 0;
  display: inline-block;
  border-radius: var(--radius-full);
  background: currentColor; /* color 는 variant 가 결정 */
  /* dot 자체에는 color 못 줌 → variant 가 .axe-status-light 의 color 를 세팅,
     dot 의 background: currentColor 로 상속. */
}

/* size — dot 만 영향, label 은 부모 font 추종. */
.axe-status-light--size-sm .axe-status-light__dot { width: 8px;  height: 8px;  }
.axe-status-light--size-md .axe-status-light__dot { width: 10px; height: 10px; }
.axe-status-light--size-lg .axe-status-light__dot { width: 12px; height: 12px; }

/* variant — currentColor 만 바꿈 (dot 은 currentColor 상속, label/timestamp 는
   별도 색 가짐).  light/dark 모두 token 으로 자동 적응. */
.axe-status-light--ok      { color: var(--success); }
.axe-status-light--warning { color: var(--warning); }
.axe-status-light--danger  { color: var(--danger);  }
.axe-status-light--muted   { color: var(--text-muted); }
.axe-status-light--running { color: var(--info);    }

/* label / timestamp 는 currentColor 무시하고 본 token 사용 — dot 만 컬러풀. */
.axe-status-light__label {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}
.axe-status-light__timestamp {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
}

/* Pulse — dot 만 깜박임.  label 영향 X.
   transform 대신 opacity + box-shadow ring 으로 — GPU 합성, layout 영향 0. */
.axe-status-light--pulse .axe-status-light__dot {
  animation: axe-status-light-pulse 1.6s ease-in-out infinite;
  box-shadow: 0 0 0 0 currentColor;
}

@keyframes axe-status-light-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in oklch, currentColor 50%, transparent); }
  70%  { box-shadow: 0 0 0 6px color-mix(in oklch, currentColor 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in oklch, currentColor 0%, transparent); }
}

@media (prefers-reduced-motion: reduce) {
  .axe-status-light--pulse .axe-status-light__dot {
    animation: none;
    box-shadow: none;
  }
}

/* ============================================================
 * MetricCard — KPI tile.
 *   layout: vertical stack (label → value → meta → sparkline).
 *   숫자 정렬: tabular-nums on value/delta/sparkline.
 * ============================================================ */
.axe-metric-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  /* sparkline 의 currentColor 상속용 base color. */
  color: var(--text-primary);
}

.axe-metric-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

.axe-metric-card__label {
  font-size: var(--text-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: var(--weight-medium);
}

.axe-metric-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  flex-shrink: 0;
}

.axe-metric-card__value {
  font-family: var(--font-display, inherit);
  font-size: var(--text-3xl);
  font-weight: var(--weight-semibold);
  line-height: 1.1;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  /* 긴 값 줄바꿈 방지 — overflow ellipsis */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.axe-metric-card__meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
}

.axe-metric-card__delta {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
  font-variant-numeric: tabular-nums;
  font-weight: var(--weight-medium);
}

.axe-metric-card__delta--up   { color: var(--success); }
.axe-metric-card__delta--down { color: var(--danger); }
.axe-metric-card__delta--flat { color: var(--text-muted); }

.axe-metric-card__delta-arrow {
  font-size: 0.85em;
  line-height: 1;
}

.axe-metric-card__delta-label {
  color: var(--text-muted);
  font-weight: var(--weight-regular);
}

.axe-metric-card__helper {
  color: var(--text-muted);
  font-size: var(--text-xs);
}

.axe-metric-card__sparkline {
  display: block;
  width: 100%;
  height: 24px;
  margin-top: var(--space-1);
  color: var(--accent);
  opacity: 0.85;
  overflow: visible;
}

/* Loading skeleton — .axe-skeleton 클래스는 안 가져오되, shimmer keyframes 는
   indicators.css 의 axe-shimmer 공유 (transform sweep — compositor-only). */
.axe-metric-card--loading {
  pointer-events: none;
}

.axe-metric-card__skel {
  position: relative;
  overflow: hidden; /* radius clip */
  background: var(--bg-subtle);
  border-radius: var(--radius-sm);
}

.axe-metric-card__skel::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in oklch, var(--text-primary) 6%, transparent),
    transparent
  );
  animation: axe-shimmer 1.4s var(--ease-in-out, ease-in-out) infinite;
}

.axe-metric-card__skel--label  { width: 40%; height: 10px; }
.axe-metric-card__skel--value  { width: 70%; height: 28px; border-radius: var(--radius-md); }
.axe-metric-card__skel--helper { width: 55%; height: 10px; }

@media (prefers-reduced-motion: reduce) {
  .axe-metric-card__skel::after {
    content: none;
  }
}

/* ============================================================
 * PipelineTable — operator status table.
 *   wrap > scroll > table.  모바일 → 가로 스크롤.
 *   row hover: bg 미세 시프트.  clickable row 는 cursor + focus ring.
 * ============================================================ */
.axe-pipeline-table {
  width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden; /* radius clip */
}

.axe-pipeline-table__scroll {
  width: 100%;
  overflow-x: auto;
  /* iOS momentum */
  -webkit-overflow-scrolling: touch;
}

.axe-pipeline-table__table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  /* 모바일에서 너무 좁아지면 가로 스크롤이 의미 있도록 min-width 잡음.
     기본 600px — column.width 합산이 더 크면 자동으로 더 넓어짐. */
  min-width: 600px;
}

.axe-pipeline-table__thead {
  background: var(--bg-subtle);
}

.axe-pipeline-table__th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border-subtle);
  white-space: nowrap;
}

.axe-pipeline-table__th--right  { text-align: right; }
.axe-pipeline-table__th--center { text-align: center; }
.axe-pipeline-table__th--status {
  width: 32px;
  padding-right: 0;
}

.axe-pipeline-table__tr {
  border-bottom: 1px solid var(--border-subtle);
  transition: background-color var(--duration-fast, 120ms) var(--ease-out, ease-out);
}

.axe-pipeline-table__tr:last-child {
  border-bottom: 0;
}

.axe-pipeline-table__tr:hover {
  background: color-mix(in oklch, var(--accent) 4%, transparent);
}

.axe-pipeline-table__tr--clickable {
  cursor: pointer;
}

.axe-pipeline-table__tr--clickable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.axe-pipeline-table__td {
  padding: var(--space-3) var(--space-4);
  color: var(--text-primary);
  /* numeric 정렬 — 좌측 텍스트는 자연스레 무시. */
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
}

.axe-pipeline-table__td--right  { text-align: right; }
.axe-pipeline-table__td--center { text-align: center; }
.axe-pipeline-table__td--status {
  width: 32px;
  padding-right: 0;
  text-align: center;
}

/* empty state */
.axe-pipeline-table__tr--empty:hover { background: transparent; }
.axe-pipeline-table__empty {
  padding: var(--space-5) var(--space-4);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* skeleton rows */
.axe-pipeline-table__tr--skeleton:hover { background: transparent; }

/* shimmer = indicators.css 의 axe-shimmer keyframes 공유 (transform sweep). */
.axe-pipeline-table__skel {
  display: inline-block;
  position: relative;
  overflow: hidden; /* radius clip */
  background: var(--bg-subtle);
  border-radius: var(--radius-sm);
}

.axe-pipeline-table__skel::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in oklch, var(--text-primary) 6%, transparent),
    transparent
  );
  animation: axe-shimmer 1.4s var(--ease-in-out, ease-in-out) infinite;
}

.axe-pipeline-table__skel--dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
}

.axe-pipeline-table__skel--bar {
  width: 70%;
  height: 12px;
}

@media (prefers-reduced-motion: reduce) {
  .axe-pipeline-table__tr {
    transition: none;
  }
  .axe-pipeline-table__skel::after {
    content: none;
  }
}

/* 모바일 viewport (≤480px) — padding 줄이고 font 더 작게.
   그래도 가로 스크롤이 우선 — table min-width 가 살아있음. */
@media (max-width: 480px) {
  .axe-pipeline-table__th,
  .axe-pipeline-table__td {
    padding: var(--space-2) var(--space-3);
  }
  .axe-pipeline-table__table {
    font-size: var(--text-xs);
  }
}

/* axe-shimmer keyframes — indicators.css 와 동일 정의 (cortex 등 선택적 번들이
 * indicators 없이 본 파일만 포함해도 동작. 동명 중복 정의는 무해 — 후승). */
@keyframes axe-shimmer {
  from { transform: translateX(-100%); }
  to { transform: translateX(100%); }
}

/* source: styles/mobile.css */
/* ============================================================
 * @axe/ui — Mobile polish + PWA (Phase 5)
 *
 * Cortex 의 globals.css (mobile section) + mysrt 의 static/style.css
 * (sticky blur header + tnum toggle) 를 SSOT 로 흡수.
 *
 * 소비자는 components.css 만 import 해도 본 파일이 자동 포함됨
 * (components.css 가 @import "./mobile.css" 함).
 *
 * 디자인 원칙:
 *  - 모든 폰트 사이즈는 CSS var 또는 16px (iOS zoom prevention) 사용
 *  - safe-area-inset 은 padding 으로만 노출 — layout shift 0
 *  - tap highlight / user-select 는 .axe-* utility 가 아닌 *전역* 적용
 *    (소비자가 매번 클래스 달 필요 없게)
 *  - 핸드폰만 영향 받는 규칙은 @media (max-width / pointer:coarse) 안에
 * ============================================================ */

/* ────────────────────────────────────────────────────────────
 * Global mobile polish — 전역 적용 (Cortex 흡수)
 * ──────────────────────────────────────────────────────────── */

/* iOS Safari 의 자동 zoom 방지 — input/textarea/select 가 16px 미만이면 focus 시 zoom.
 * 데스크탑은 .axe-input 의 var(--text-sm) 유지를 위해 모바일 only. */
@media (max-width: 767.98px) {
  input,
  textarea,
  select {
    font-size: 16px;
  }
}

/* 페이지 전체 pull-to-refresh 차단 — 우리 usePullToRefresh 와 충돌 방지.
 * 개별 .axe-scroll-container 에서 overscroll-behavior: contain 재정의 가능. */
html {
  overscroll-behavior-y: contain;
}

/* 모바일 tap highlight 제거 — iOS/Android 의 회색 박스 안 보이게. */
* {
  -webkit-tap-highlight-color: transparent;
}

/* App-like UI 요소는 텍스트 선택 차단 (실수 방지). */
button,
nav,
header,
footer,
[role="button"],
[role="tab"],
[role="menuitem"] {
  -webkit-user-select: none;
  user-select: none;
}

/* 본문/입력 영역은 선택 가능 — 위 규칙 override. */
main,
textarea,
input,
[contenteditable="true"],
[role="log"],
article,
.axe-prose,
.axe-message__body {
  -webkit-user-select: text;
  user-select: text;
}

/* iOS momentum scroll — 컨테이너 ref 용 utility. */
.axe-scroll-container {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* ────────────────────────────────────────────────────────────
 * Safe-area utility classes
 * env(safe-area-inset-*) 는 iOS notch / Dynamic Island / Android gesture bar
 * 영역을 피하기 위한 OS 제공 값.  CSS var 로 노출해 .axe-* 가 자유롭게 참조.
 *
 * iOS 에서는 <meta name="viewport" content="... viewport-fit=cover">
 * 가 root layout 에 있어야 env() 가 0 이 아닌 값을 반환.
 * ──────────────────────────────────────────────────────────── */
:root {
  --axe-safe-top: env(safe-area-inset-top, 0px);
  --axe-safe-bottom: env(safe-area-inset-bottom, 0px);
  --axe-safe-left: env(safe-area-inset-left, 0px);
  --axe-safe-right: env(safe-area-inset-right, 0px);
}

.axe-safe-area {
  padding-top: var(--axe-safe-top);
  padding-bottom: var(--axe-safe-bottom);
  padding-left: var(--axe-safe-left);
  padding-right: var(--axe-safe-right);
}
.axe-safe-area-top    { padding-top: var(--axe-safe-top); }
.axe-safe-area-bottom { padding-bottom: var(--axe-safe-bottom); }
.axe-safe-area-x      {
  padding-left: var(--axe-safe-left);
  padding-right: var(--axe-safe-right);
}

/* ────────────────────────────────────────────────────────────
 * Sticky blur header — mysrt 패턴 SSOT 화.
 *
 * 페이지 최상단에 fixed-style 헤더 → 스크롤 시 blur + saturate 로 깊이감.
 * .axe-topnav 가 이미 같은 패턴인데, 본 utility 는 *non-nav* 영역 (예:
 * chat thread 상단의 conversation title bar, IC report toolbar) 용.
 *
 * 소비:
 *   <header className="axe-sticky-blur axe-safe-area-top"> ... </header>
 * ──────────────────────────────────────────────────────────── */
.axe-sticky-blur {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky, 50);
  background: color-mix(in oklch, var(--bg-base) 82%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--border-subtle);
}

/* ────────────────────────────────────────────────────────────
 * Tabular numbers utility — mysrt 의 tnum toggle 흡수.
 *
 * 재무 숫자 (portfolio KPI, IC report 의 valuation/IRR 컬럼,
 * payslip 의 금액 컬럼) 는 fixed-width 숫자가 정렬 정확도에 필수.
 * 본 utility 를 셀/컬럼에 달면 monospace 숫자 폭 적용 — 다른 폰트는 그대로.
 *
 * 쓰임:
 *   - Portfolio KPI dashboard 의 금액/지분율
 *   - IC report 의 valuation 표, IRR 컬럼
 *   - Payslip / payroll 의 amount 컬럼
 *   - Countdown / poll count 같은 변화하는 숫자
 *
 * .axe-table 에는 이미 font-variant-numeric: tabular-nums 가 있음.
 * 본 utility 는 *임의의 요소* 에 같은 효과를 주기 위함.
 * ──────────────────────────────────────────────────────────── */
.axe-tabular-nums {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ────────────────────────────────────────────────────────────
 * PWA standalone display — iOS "홈 화면에 추가" / Android PWA 설치 후.
 *
 * standalone 모드에서는 브라우저 chrome 이 없어서 safe-area 가 더 중요.
 * body 전역에 적용 — 모든 페이지 자동 보호.
 * ──────────────────────────────────────────────────────────── */
@media (display-mode: standalone) {
  body {
    padding-top: var(--axe-safe-top);
    padding-bottom: var(--axe-safe-bottom);
    padding-left: var(--axe-safe-left);
    padding-right: var(--axe-safe-right);
  }
}

/* ────────────────────────────────────────────────────────────
 * Pull-to-refresh indicator slot — usePullToRefresh 의 시각 보조 utility.
 *
 * hook 은 logic 만 제공하지만, 가장 흔한 indicator (당김 progress 막대 +
 * refreshing spinner) 의 시각 어휘는 SSOT 에 두는 게 합리적.
 * 소비자는 <div className="axe-ptr-indicator" style={{ height: distance }} /> 식.
 * ──────────────────────────────────────────────────────────── */
.axe-ptr-indicator {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  /* height transition 없음 (의도적) — usePullToRefresh 가 매 프레임 height 를
     직접 구동하므로 transition 이 겹치면 이중 애니메이션 + layout jank.
     release 시 collapse 애니메이션도 hook 책임 (height 는 layout 속성이라
     transform 대체 불가 — 아래 콘텐츠를 밀어내야 함). */
}

/* source: styles/agent.css */
/* ============================================================
 * Phase 8 — Agent composites (AgentExecutor / StreamingTable
 *           / MultiModalChatInput / attach chip / etc.)
 *
 * 본 파일은 components.css 가 import 하지 않음 (Phase 8 owner 가
 * 명시적 opt-in). 새 컴포넌트가 통합 stable 되면 components.css 에
 * @import "./agent.css"; 한 줄 추가 예정.
 * ============================================================ */

/* ---------- AgentExecutor ---------- */
.axe-agent-executor {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  background: var(--bg-base);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.axe-agent-executor__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--space-4) var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  .axe-agent-executor__scroll {
    scroll-behavior: auto;
  }
}

.axe-agent-executor__empty {
  padding: var(--space-8) var(--space-4);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

.axe-agent-executor__user-content {
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--text-primary);
}

.axe-agent-executor__tools {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.axe-agent-executor__tools--free {
  margin: var(--space-2) 0 0;
}

.axe-agent-executor__attachments {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.axe-agent-executor__streaming-hint {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  margin-top: var(--space-2);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
}

.axe-agent-executor__input {
  flex: 0 0 auto;
  padding: var(--space-3) var(--space-4) var(--space-4);
  border-top: 1px solid var(--border-subtle);
  background: var(--bg-base);
}

/* ---------- MultiModalChatInput — extends .axe-chat-input ---------- */
.axe-chat-input--dragover {
  border-color: var(--accent);
  box-shadow: var(--ring);
}

.axe-chat-input--disabled {
  opacity: 0.6;
  pointer-events: none;
}

.axe-chat-input__drop-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  background: color-mix(in oklch, var(--accent) 8%, transparent);
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  border-radius: var(--radius-lg);
}

/* drop overlay 위치 잡으려면 chat-input 이 position:relative 필요 — Phase 8 에서만 적용. */
.axe-agent-executor .axe-chat-input,
.axe-chat-input:has(.axe-chat-input__drop-overlay) {
  position: relative;
}

.axe-attach-file-input {
  display: none;
}

.axe-attach-button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  background: transparent;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--text-xs);
  font-family: inherit;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}
.axe-attach-button:hover:not(:disabled) {
  background: var(--bg-subtle);
  color: var(--text-primary);
  border-color: var(--border-default);
}
.axe-attach-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ---------- attach chip ---------- */
.axe-attach-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.axe-attach-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  max-width: 240px;
  overflow: hidden;
}

.axe-attach-chip__thumb {
  width: 24px;
  height: 24px;
  border-radius: var(--radius-sm);
  object-fit: cover;
  flex-shrink: 0;
}

.axe-attach-chip__icon {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elevated);
  border-radius: var(--radius-sm);
  color: var(--text-tertiary);
  flex-shrink: 0;
  font-size: var(--text-sm);
}

.axe-attach-chip__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-primary);
  min-width: 0;
}

.axe-attach-chip__size {
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex-shrink: 0;
}

.axe-attach-chip__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  background: transparent;
  border: 0;
  border-radius: var(--radius-full);
  color: var(--text-tertiary);
  cursor: pointer;
  font-size: var(--text-base);
  line-height: 1;
  padding: 0;
  flex-shrink: 0;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}
.axe-attach-chip__remove:hover {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

/* compact = AgentExecutor 의 사용자 메시지 안에 표시되는 mini chip */
.axe-attach-chip--compact {
  padding: 2px var(--space-2);
  max-width: 200px;
}
.axe-attach-chip--compact .axe-attach-chip__thumb,
.axe-attach-chip--compact .axe-attach-chip__icon {
  width: 18px;
  height: 18px;
}

/* ---------- StreamingTable ---------- */
.axe-streaming-table {
  width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.axe-streaming-table__progress {
  height: 2px;
  background: var(--bg-subtle);
  overflow: hidden; /* scaleX 된 bar 가 track 밖으로 안 새게 clip. */
}
/* width 대신 transform scaleX — 연속 갱신되는 요소라 layout 안 건드리고
 * compositor 에서만 처리.  진행률은 --axe-progress (0..1) 로 주입. */
.axe-streaming-table__progress-bar {
  height: 100%;
  width: 100%;
  background: var(--accent);
  transform-origin: left;
  transform: scaleX(var(--axe-progress, 1)); /* 기본 1: 구 마크업(inline width:%)은 width 가 그대로 보이도록 (CSS-only 소비자 하위호환) */
  transition: transform var(--duration-base, 200ms) var(--ease-out);
}

.axe-streaming-table__scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.axe-streaming-table__table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  min-width: 480px;
}

.axe-streaming-table__thead {
  background: var(--bg-subtle);
}

.axe-streaming-table__th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border-subtle);
  white-space: nowrap;
}
.axe-streaming-table__th--right { text-align: right; }
.axe-streaming-table__th--center { text-align: center; }

.axe-streaming-table__tr {
  border-bottom: 1px solid var(--border-subtle);
}
.axe-streaming-table__tr:last-child {
  border-bottom: 0;
}

.axe-streaming-table__td {
  padding: var(--space-3) var(--space-4);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
}
.axe-streaming-table__td--right { text-align: right; }
.axe-streaming-table__td--center { text-align: center; }

.axe-streaming-table__tr--empty:hover,
.axe-streaming-table__tr--pending:hover {
  background: transparent;
}

.axe-streaming-table__empty {
  text-align: center;
  color: var(--text-muted);
  padding: var(--space-5) var(--space-4);
}

.axe-streaming-table__pending {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
}

/* row fade-in */
.axe-streaming-table__tr--in {
  animation: axe-stream-row-in 220ms var(--ease-out, ease-out) both;
}

@keyframes axe-stream-row-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .axe-streaming-table__tr--in {
    animation: none;
  }
  .axe-streaming-table__progress-bar {
    transition: none;
  }
}

/* source: styles/data-display.css */
/* ============================================================
 * Data display (Phase 14 Wave 5)
 *   DataTable · Pagination · Chart (recharts wrap) · DescriptionList (.axe-kv)
 *
 *   본 파일은 core-data Consumer Kit 프로파일에 포함된다 (export-axe-ui.mjs 의
 *   CORE_DATA_SOURCES). cortex 처럼 core-data 로 소비하는 서비스가 쓰는 데이터
 *   표시 primitive 는 data-views.css 가 아니라 여기 둔다 — 그쪽은 프로파일 밖이라
 *   투영에서 통째로 빠진다.
 *
 *   Phase 7 dashboard.css 와 별도 — Pipeline 은 운영자 status row,
 *   DataTable 은 일반 데이터 + 정렬/페이징.  스타일 분리해서 tree-shake
 *   가능, showcase page 에서 본 파일만 import.
 *
 *   원칙
 *     · token-only — Tailwind 0, hard-coded color 0.
 *     · CSS-only animation (hover transition, skeleton shimmer).
 *     · prefers-reduced-motion: reduce 시 모든 motion 정지/완화.
 *     · light/dark 자동 — CSS var 만 사용.
 * ============================================================ */

/* ============================================================
 * DataTable — sortable, paginatable generic data table.
 *   wrap > scroll > table.  PipelineTable 과 마크업 유사하지만
 *   sortable header 가 <button> 으로 들어가는 차이.
 * ============================================================ */
.axe-data-table {
  width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden; /* radius clip */
}

.axe-data-table__scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.axe-data-table--sticky .axe-data-table__scroll {
  max-height: 480px;
  overflow-y: auto;
}

.axe-data-table__table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  min-width: 600px;
}

.axe-data-table__thead {
  background: var(--bg-subtle);
}

.axe-data-table--sticky .axe-data-table__thead {
  position: sticky;
  top: 0;
  z-index: 1;
}

.axe-data-table__th {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border-subtle);
  white-space: nowrap;
}

.axe-data-table__th--right  { text-align: right; }
.axe-data-table__th--center { text-align: center; }

.axe-data-table__th--active {
  color: var(--text-primary);
}

.axe-data-table__th--sortable {
  padding: 0; /* button 이 padding 보유 */
}

.axe-data-table__sort-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  width: 100%;
  background: transparent;
  border: 0;
  padding: var(--space-3) var(--space-4);
  font-size: inherit;
  font-weight: inherit;
  color: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  text-align: inherit;
  cursor: pointer;
  font-family: inherit;
  transition: color var(--duration-fast, 120ms) var(--ease-out, ease-out);
}

.axe-data-table__th--right .axe-data-table__sort-btn  { justify-content: flex-end; }
.axe-data-table__th--center .axe-data-table__sort-btn { justify-content: center; }

.axe-data-table__sort-btn:hover {
  color: var(--text-primary);
}

.axe-data-table__sort-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: var(--radius-sm);
}

.axe-data-table__sort-arrow {
  font-size: 0.8em;
  color: var(--text-muted);
  line-height: 1;
}

.axe-data-table__th--active .axe-data-table__sort-arrow {
  color: var(--accent);
}

.axe-data-table__tr {
  border-bottom: 1px solid var(--border-subtle);
  transition: background-color var(--duration-fast, 120ms) var(--ease-out, ease-out);
}

.axe-data-table__tr:last-child {
  border-bottom: 0;
}

.axe-data-table__tr:hover {
  background: color-mix(in oklch, var(--accent) 4%, transparent);
}

.axe-data-table__tr--clickable {
  cursor: pointer;
}

.axe-data-table__tr--clickable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.axe-data-table__td {
  padding: var(--space-3) var(--space-4);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
}

.axe-data-table__td--right  { text-align: right; }
.axe-data-table__td--center { text-align: center; }

/* empty state */
.axe-data-table__tr--empty:hover { background: transparent; }
.axe-data-table__empty {
  padding: var(--space-6) var(--space-4);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* skeleton rows */
.axe-data-table__tr--skeleton:hover { background: transparent; }

/* shimmer = indicators.css 의 axe-shimmer keyframes 공유 (transform sweep). */
.axe-data-table__skel {
  display: inline-block;
  width: 70%;
  height: 12px;
  position: relative;
  overflow: hidden; /* radius clip */
  background: var(--bg-subtle);
  border-radius: var(--radius-sm);
}

.axe-data-table__skel::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent,
    color-mix(in oklch, var(--text-primary) 6%, transparent),
    transparent
  );
  animation: axe-shimmer 1.4s var(--ease-in-out, ease-in-out) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .axe-data-table__tr,
  .axe-data-table__sort-btn {
    transition: none;
  }
  .axe-data-table__skel::after {
    content: none;
  }
}

@media (max-width: 480px) {
  .axe-data-table__th,
  .axe-data-table__td,
  .axe-data-table__sort-btn {
    padding: var(--space-2) var(--space-3);
  }
  .axe-data-table__table {
    font-size: var(--text-xs);
  }
}

/* ============================================================
 * Pagination — page nav.
 *   info | list (이전 + page btns + 다음).
 *   compact 시 list 안의 페이지 버튼이 "current / total" 텍스트로 치환.
 * ============================================================ */
.axe-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  font-variant-numeric: tabular-nums;
}

.axe-pagination__info {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.axe-pagination__info-range {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}

.axe-pagination__info-sep {
  color: var(--text-muted);
}

.axe-pagination__info-total {
  color: var(--text-secondary);
}

.axe-pagination__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.axe-pagination__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 var(--space-2);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition:
    background-color var(--duration-fast, 120ms) var(--ease-out, ease-out),
    color var(--duration-fast, 120ms) var(--ease-out, ease-out),
    border-color var(--duration-fast, 120ms) var(--ease-out, ease-out);
}

.axe-pagination__btn:hover:not(:disabled):not(.axe-pagination__btn--active) {
  background: var(--bg-subtle);
  color: var(--text-primary);
}

.axe-pagination__btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.axe-pagination__btn:disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

.axe-pagination__btn--active {
  background: var(--accent);
  color: var(--accent-fg);
  border-color: var(--accent);
  cursor: default;
}

.axe-pagination__btn--nav {
  font-size: var(--text-lg);
  line-height: 1;
}

.axe-pagination__ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 32px;
  color: var(--text-muted);
  font-size: var(--text-sm);
  user-select: none;
}

/* size sm */
.axe-pagination--size-sm .axe-pagination__btn {
  min-width: 28px;
  height: 28px;
  font-size: var(--text-xs);
}
.axe-pagination--size-sm .axe-pagination__btn--nav {
  font-size: var(--text-base);
}
.axe-pagination--size-sm .axe-pagination__ellipsis {
  height: 28px;
  font-size: var(--text-xs);
}

/* compact 모바일 */
.axe-pagination--compact {
  justify-content: center;
}
.axe-pagination__compact-label {
  display: inline-flex;
  align-items: baseline;
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.axe-pagination__compact-current {
  font-weight: var(--weight-semibold);
}
.axe-pagination__compact-sep {
  color: var(--text-muted);
  padding: 0 var(--space-1);
}
.axe-pagination__compact-total {
  color: var(--text-secondary);
}

@media (prefers-reduced-motion: reduce) {
  .axe-pagination__btn {
    transition: none;
  }
}

/* ============================================================
 * Chart — recharts wrap container.
 *   recharts SVG 가 컨테이너 100% 차지 → axe-chart 가 height 지정자.
 *   tooltip 은 portal 아닌 inline div — axe-chart__tooltip 으로 자체 styling.
 *
 *   색 매핑 (Chart.tsx 와 동기화):
 *     · series color: --accent → --success → --warning → --danger → --info 순환
 *     · axis tick:    --text-secondary
 *     · grid line:    --border-subtle  (strokeDasharray 3 3)
 *     · tooltip bg:   --bg-elevated  border: --border-subtle
 *     · dashed line:  strokeDasharray 5 4  — series.dashed=true 시
 *     · gradient area: 0%→35% / 100%→2% (의미: 최근일수록 진함)
 * ============================================================ */
.axe-chart {
  width: 100%;
  color: var(--text-primary);
}

/* tooltip — recharts content 안에서 사용 */
.axe-chart__tooltip {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md, var(--shadow-sm, 0 2px 8px rgb(0 0 0 / 0.1)));
  padding: var(--space-2) var(--space-3);
  min-width: 120px;
  font-size: var(--text-xs);
  color: var(--text-primary);
  pointer-events: none;
}

.axe-chart__tooltip-label {
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  margin-bottom: var(--space-1);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--border-subtle);
}

.axe-chart__tooltip-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.axe-chart__tooltip-row {
  display: grid;
  grid-template-columns: 12px 1fr auto;
  align-items: center;
  gap: var(--space-2);
}

.axe-chart__tooltip-swatch {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-sm);
  display: inline-block;
}

.axe-chart__tooltip-name {
  color: var(--text-secondary);
}

.axe-chart__tooltip-value {
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}

/* recharts text default 가 SVG fill — focus ring 은 SVG 가 자체 처리.
   reduced-motion 은 컴포넌트 prop 으로 animation false (Chart.tsx).  */

/* ============================================================
 *  DescriptionList (.axe-kv) — 상세 표면의 키·값 목록.
 *
 *  <dl> 이 곧 grid: 왼쪽 고정 폭 key 열 + 나머지를 채우는 value 열.  cortex 의
 *  artifact 상세와 gate 의 detail aside 가 각자 로컬 CSS 로 들고 있던 같은 모양을
 *  SSOT 로 흡수한다.  key 열 폭은 표면마다 --axe-kv-key-w 로 조정 (기본 8.75rem
 *  = 140px, cortex 실측치).  ≤30rem 에서는 한 열로 쌓여 320px 뷰포트와 200%
 *  확대에서도 value 가 눌리지 않는다.
 *
 *  마크업은 두 형태 모두 유효 (HTML 이 dl > div > dt+dd 를 허용):
 *    평면   <dl class="axe-kv"><dt class="axe-kv__key">…<dd class="axe-kv__value">…
 *    래핑   <dl class="axe-kv"><div class="axe-kv__row"><dt …><dd …></div>
 *  래퍼는 display: contents 라 박스를 만들지 않고 grid 참여만 넘긴다.
 * ============================================================ */
.axe-kv {
  display: grid;
  grid-template-columns: var(--axe-kv-key-w, 8.75rem) minmax(0, 1fr);
  gap: var(--space-2) var(--space-4);
  margin: 0;
  font-size: var(--text-sm);
}

.axe-kv--compact {
  gap: var(--space-1) var(--space-3);
}

.axe-kv__row {
  display: contents;
}

.axe-kv__key {
  margin: 0;
  color: var(--text-muted);
  font-weight: var(--weight-regular);
  overflow-wrap: anywhere; /* 끊을 곳 없는 긴 키가 고정 폭 열을 넘지 않게 (value 와 동일) */
}

.axe-kv__value {
  margin: 0;
  color: var(--text-primary);
  overflow-wrap: anywhere;
}

/* 좁은 폭 — 한 열 stack.  행 사이만 벌려 key·value 짝이 붙어 보이게 한다
   (평면 마크업은 dd+dt 인접, 래핑 마크업은 row+row 인접으로 각각 잡는다). */
@media (max-width: 30rem) {
  .axe-kv {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--space-1);
  }

  .axe-kv__value + .axe-kv__key,
  .axe-kv__row + .axe-kv__row .axe-kv__key {
    margin-top: var(--space-2);
  }
}

/* axe-shimmer keyframes — indicators.css 와 동일 정의 (cortex 등 선택적 번들이
 * indicators 없이 본 파일만 포함해도 동작. 동명 중복 정의는 무해 — 후승). */
@keyframes axe-shimmer {
  from { transform: translateX(-100%); }
  to { transform: translateX(100%); }
}

/* source: styles/menus.css */
/* ============================================================
 * @axe/ui — Menus group (AlertDialog · Accordion · DropdownMenu)
 *
 *  Phase 14 Wave 5.  세 컴포넌트 모두 Radix 위 thin wrapper.
 *
 *  - AlertDialog : Dialog 와 비주얼 90% 동일 (overlay + 카드).  차이는
 *                  close X 없음 + footer 의 Cancel/Action 강조 + destructive variant.
 *  - Accordion   : chevron rotate 0deg→90deg + smooth height collapse
 *                  (Radix --radix-accordion-content-height 변수).
 *  - DropdownMenu: 메뉴 표면 + item highlighted state + danger variant +
 *                  separator + checkbox/radio indicator + Kbd shortcut + sub-menu.
 *
 *  공통: prefers-reduced-motion 시 모든 트랜지션/애니메이션 off.
 *        owner 컴포넌트의 components.css 는 건드리지 않음 — 본 파일은
 *        독립 import (소비자가 명시 import 하거나 추후 owner 가 통합).
 * ============================================================ */

/* ────────────────────────────────────────────────────────────
 * AlertDialog
 *   - Dialog 의 overlay/content 키프레임을 재사용하지 않고 자체 정의
 *     (소비자가 menus.css 만 import 해도 작동해야 하므로).
 *   - size: sm 440 default / md 560 / lg 720.  full/xl 없음 — confirm 모달은 작게.
 * ──────────────────────────────────────────────────────────── */
.axe-alert-dialog__overlay {
  position: fixed;
  inset: 0;
  background: var(--bg-overlay);
  backdrop-filter: blur(2px);
  z-index: var(--z-modal);   /* Sheet (var(--z-overlay)=1000) 보다 위 */
  animation: axe-alert-dialog-overlay-in 160ms ease-out;
}
.axe-alert-dialog__overlay[data-state="closed"] {
  animation: axe-alert-dialog-overlay-out 120ms ease-in forwards;
}

.axe-alert-dialog__content {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(100vw - 2 * var(--space-4));
  max-height: calc(100dvh - 2 * var(--space-4));
  overflow: auto;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl); /* 대형 overlay 표면 = 16px (radius mapping) */
  box-shadow: var(--shadow-lg);
  padding: var(--space-6);
  z-index: calc(var(--z-modal) + 1);
  animation: axe-alert-dialog-content-in 180ms cubic-bezier(0.16, 1, 0.3, 1);
}
.axe-alert-dialog__content[data-state="closed"] {
  animation: axe-alert-dialog-content-out 140ms ease-in forwards;
}
.axe-alert-dialog__content:focus { outline: none; }

.axe-alert-dialog__content--sm { max-width: 440px; }
.axe-alert-dialog__content--md { max-width: 560px; }
.axe-alert-dialog__content--lg { max-width: 720px; }

/* Header — close X 없음 → padding-right 0 (Dialog 와 다른 점). */
.axe-alert-dialog__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
}

.axe-alert-dialog__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: var(--text-lg);
  line-height: 1.3;
  color: var(--text-primary);
  margin: 0;
}

.axe-alert-dialog__description {
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--text-secondary);
  margin: 0;
}

.axe-alert-dialog__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}

/* Cancel/Action 은 .axe-btn 위에 얹는 미세 보정만 — 강제 우정렬 + 최소 폭. */
.axe-alert-dialog__cancel,
.axe-alert-dialog__action {
  min-width: 80px;
  justify-content: center;
}

@keyframes axe-alert-dialog-overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes axe-alert-dialog-overlay-out {
  to { opacity: 0; }
}
@keyframes axe-alert-dialog-content-in {
  from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes axe-alert-dialog-content-out {
  to { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
}

/* ────────────────────────────────────────────────────────────
 * Accordion
 *   - item 사이 border-bottom (마지막 item 은 제거).
 *   - trigger = 전폭 버튼, chevron 우측, hover bg-subtle.
 *   - content = height transition (closed: 0 → open: var(--radix-accordion-content-height)).
 * ──────────────────────────────────────────────────────────── */
.axe-accordion__item {
  border-bottom: 1px solid var(--border-subtle);
}
.axe-accordion__item:last-child {
  border-bottom: 0;
}

.axe-accordion__header {
  margin: 0;
  display: flex;
}

.axe-accordion__trigger {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3) var(--space-1);
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.4;
  text-align: left;
  border-radius: var(--radius-sm);
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}
.axe-accordion__trigger:hover {
  background: var(--bg-subtle);
}
.axe-accordion__trigger:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.axe-accordion__trigger-label {
  flex: 1;
  min-width: 0;
}

.axe-accordion__chevron {
  flex: 0 0 auto;
  color: var(--text-tertiary);
  transition: transform 180ms var(--ease-out);
}
.axe-accordion__trigger[data-state="open"] .axe-accordion__chevron {
  transform: rotate(90deg);
  color: var(--text-primary);
}

.axe-accordion__content {
  overflow: hidden;
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--text-secondary);
}
.axe-accordion__content[data-state="open"] {
  animation: axe-accordion-down 200ms var(--ease-out);
}
.axe-accordion__content[data-state="closed"] {
  animation: axe-accordion-up 160ms ease-in forwards;
}
.axe-accordion__content-inner {
  padding: 0 var(--space-1) var(--space-4);
}

@keyframes axe-accordion-down {
  from { height: 0; opacity: 0; }
  to   { height: var(--radix-accordion-content-height); opacity: 1; }
}
@keyframes axe-accordion-up {
  from { height: var(--radix-accordion-content-height); opacity: 1; }
  to   { height: 0; opacity: 0; }
}

/* ────────────────────────────────────────────────────────────
 * Collapsible
 *   - 단일 disclosure 영역 (Accordion 의 stack 없이 한 영역만 접기/펴기).
 *   - trigger = 전폭 버튼 (children 직접 전달 시), chevron 우측, hover bg-subtle.
 *   - content = height transition (closed: 0 → open: var(--radix-collapsible-content-height)).
 * ──────────────────────────────────────────────────────────── */
.axe-collapsible__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3) var(--space-1);
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.4;
  text-align: left;
  border-radius: var(--radius-sm);
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}
.axe-collapsible__trigger:hover {
  background: var(--bg-subtle);
}
.axe-collapsible__trigger:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.axe-collapsible__trigger-label {
  flex: 1;
  min-width: 0;
}

.axe-collapsible__chevron {
  flex: 0 0 auto;
  color: var(--text-tertiary);
  transition: transform 180ms var(--ease-out);
}
.axe-collapsible__trigger[data-state="open"] .axe-collapsible__chevron {
  transform: rotate(90deg);
  color: var(--text-primary);
}

.axe-collapsible__content {
  overflow: hidden;
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--text-secondary);
}
.axe-collapsible__content[data-state="open"] {
  animation: axe-collapsible-down 200ms var(--ease-out);
}
.axe-collapsible__content[data-state="closed"] {
  animation: axe-collapsible-up 160ms ease-in forwards;
}
.axe-collapsible__content-inner {
  padding: 0 var(--space-1) var(--space-4);
}

@keyframes axe-collapsible-down {
  from { height: 0; opacity: 0; }
  to   { height: var(--radix-collapsible-content-height); opacity: 1; }
}
@keyframes axe-collapsible-up {
  from { height: var(--radix-collapsible-content-height); opacity: 1; }
  to   { height: 0; opacity: 0; }
}

/* ────────────────────────────────────────────────────────────
 * DropdownMenu
 *   - Popover 와 표면은 비슷 (elevated bg + border + shadow) 이나
 *     item highlighted 상태 (Radix data-highlighted) 가 메뉴 특유.
 *   - Item: 좌측 indicator/icon · 가운데 label · 우측 shortcut.
 *   - danger variant 는 텍스트 + highlighted bg 가 danger 톤.
 *   - separator: 1px var(--border-subtle).
 *   - sub-menu: SubContent 도 같은 표면 스타일 + 살짝 더 가벼운 그림자.
 * ──────────────────────────────────────────────────────────── */
.axe-dropdown-menu__content {
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: var(--space-1);
  min-width: 200px;
  max-width: min(90vw, 320px);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.4;
  z-index: var(--z-overlay);
  outline: none;
  transform-origin: var(--radix-dropdown-menu-content-transform-origin);
}
.axe-dropdown-menu__content[data-state="open"] {
  animation: axe-dropdown-menu-in 160ms var(--ease-out);
}
.axe-dropdown-menu__content[data-state="closed"] {
  animation: axe-dropdown-menu-out 120ms ease-in forwards;
}

.axe-dropdown-menu__sub-content {
  box-shadow: var(--shadow-md);
}

.axe-dropdown-menu__label {
  padding: var(--space-2) var(--space-3) var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-tertiary);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.axe-dropdown-menu__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  padding-left: var(--space-3);
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text-primary);
  user-select: none;
  outline: none;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}
.axe-dropdown-menu__item[data-highlighted] {
  background: var(--bg-subtle);
  color: var(--text-primary);
}
.axe-dropdown-menu__item[data-disabled] {
  color: var(--text-muted);
  cursor: not-allowed;
  pointer-events: none;
}

/* checkbox/radio item — indicator 좌측 고정 폭 확보 (체크 안 됐을 때도 정렬 유지). */
.axe-dropdown-menu__item--checkbox,
.axe-dropdown-menu__item--radio {
  padding-left: var(--space-2);
}
.axe-dropdown-menu__item-indicator {
  flex: 0 0 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
}

.axe-dropdown-menu__item-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  color: var(--text-tertiary);
}

.axe-dropdown-menu__item-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* danger variant — 글자 색을 danger 로, highlighted 시 danger-soft 배경. */
.axe-dropdown-menu__item--danger {
  color: var(--danger);
}
.axe-dropdown-menu__item--danger .axe-dropdown-menu__item-icon {
  color: var(--danger);
}
.axe-dropdown-menu__item--danger[data-highlighted] {
  background: color-mix(in oklch, var(--danger) 12%, transparent);
  color: var(--danger);
}

/* sub-trigger chevron — 우측 ▶. */
.axe-dropdown-menu__sub-chevron {
  flex: 0 0 auto;
  color: var(--text-tertiary);
  margin-left: auto;
}
.axe-dropdown-menu__item--sub-trigger[data-state="open"] {
  background: var(--bg-subtle);
}

.axe-dropdown-menu__separator {
  /* Radix Separator 는 <div> 지만 rail-selectors 계약 픽스처와 CSS-only 소비자
   * (layer·gate)는 <hr> 로 찍는다 — UA 의 hr inset 테두리를 리셋하지 않으면
   * 1px 배경선 위에 기본 테두리가 겹쳐 다크에서 밝고 두꺼운 줄이 된다. */
  border: 0;
  height: 1px;
  background: var(--border-subtle);
  margin: var(--space-1) calc(-1 * var(--space-1));
}

/* Shortcut — Kbd 슬롯, 우측 정렬 + 작은 폰트.  Kbd 자체 스타일은 그대로. */
.axe-dropdown-menu__shortcut {
  margin-left: auto;
  padding-left: var(--space-3);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  display: inline-flex;
}

.axe-dropdown-menu__arrow {
  fill: var(--bg-elevated);
  filter: drop-shadow(0 1px 0 var(--border-subtle));
}

@keyframes axe-dropdown-menu-in {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes axe-dropdown-menu-out {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(0.96); }
}

/* ────────────────────────────────────────────────────────────
 * Reduced motion
 * ──────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .axe-alert-dialog__overlay,
  .axe-alert-dialog__overlay[data-state="closed"],
  .axe-alert-dialog__content,
  .axe-alert-dialog__content[data-state="closed"],
  .axe-accordion__content,
  .axe-accordion__content[data-state="open"],
  .axe-accordion__content[data-state="closed"],
  .axe-accordion__chevron,
  .axe-collapsible__content,
  .axe-collapsible__content[data-state="open"],
  .axe-collapsible__content[data-state="closed"],
  .axe-collapsible__chevron,
  .axe-dropdown-menu__content,
  .axe-dropdown-menu__content[data-state="closed"] {
    animation: none !important;
    transition: none !important;
  }
}

/* source: styles/feedback.css */
/* ============================================================
 * Phase 14 Wave 5 — Feedback group  (EmptyState · ErrorBoundary · StatusBanner)
 *
 * 본 파일은 core-data Consumer Kit 프로파일에 포함된다 (export-axe-ui.mjs 의
 * CORE_DATA_SOURCES). 상태 피드백 프리미티브는 여기에 둔다 — core-data 로
 * 소비하는 서비스(cortex 등)가 쓰는 표면이 프로파일 밖으로 새지 않게 한다.
 *
 *  - 본 파일은 components.css 가 import 하지 않음 (owner 가 통합).
 *    showcase 와 통합 전 까지는 page 가 직접 side-effect import.
 *  - 표면은 transparent 또는 elevated.  semantic 색은 icon/border 만.
 *  - reduced-motion 존중, dark/light CSS var 자동.
 * ============================================================ */

/* ────────────────────────────────────────────────────────────
 * EmptyState
 *   - center-aligned column.  background: transparent → Card 안/밖 모두 자연.
 *   - icon → title → description → actions 순서.
 *   - size 가 padding + icon box + 폰트 크기 비례.
 *   - tone 이 icon 색 + (subtle) border accent 결정.
 * ──────────────────────────────────────────────────────────── */
.axe-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-3);
  padding: var(--space-7) var(--space-5);
  background: transparent;
  border: 1px dashed var(--border-subtle);
  border-radius: var(--radius-lg);
  color: var(--text-primary);
}

.axe-empty-state__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-full);
  background: var(--bg-subtle);
  color: var(--text-tertiary);
  font-size: 24px;
  line-height: 1;
}

.axe-empty-state__title {
  font-family: var(--font-display, var(--font-sans));
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.3;
}

.axe-empty-state__description {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: 1.5;
  max-width: 48ch;
}

.axe-empty-state__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* ── size variants ── */
.axe-empty-state--size-sm {
  padding: var(--space-5) var(--space-4);
  gap: var(--space-2);
}
.axe-empty-state--size-sm .axe-empty-state__icon {
  width: 36px;
  height: 36px;
  font-size: 18px;
}
.axe-empty-state--size-sm .axe-empty-state__title {
  font-size: var(--text-base);
}
.axe-empty-state--size-sm .axe-empty-state__description {
  font-size: var(--text-xs);
}

.axe-empty-state--size-lg {
  padding: var(--space-8) var(--space-6);
  gap: var(--space-4);
}
.axe-empty-state--size-lg .axe-empty-state__icon {
  width: 64px;
  height: 64px;
  font-size: 32px;
}
.axe-empty-state--size-lg .axe-empty-state__title {
  font-size: var(--text-xl);
}

/* ── tone variants — icon tint + border accent (subtle) ── */
.axe-empty-state--tone-success {
  border-color: color-mix(in srgb, var(--success) 35%, var(--border-subtle));
}
.axe-empty-state--tone-success .axe-empty-state__icon {
  background: var(--success-soft);
  color: var(--success);
}

.axe-empty-state--tone-warning {
  border-color: color-mix(in srgb, var(--warning) 35%, var(--border-subtle));
}
.axe-empty-state--tone-warning .axe-empty-state__icon {
  background: var(--warning-soft);
  color: var(--warning);
}

.axe-empty-state--tone-danger {
  border-color: color-mix(in srgb, var(--danger) 35%, var(--border-subtle));
}
.axe-empty-state--tone-danger .axe-empty-state__icon {
  background: var(--danger-soft);
  color: var(--danger);
}

/* ────────────────────────────────────────────────────────────
 * ErrorBoundary — default fallback 의 wrapper.
 *   - Callout(variant="danger") 가 본체.  여기서는 spacing + 액션 row 만.
 *   - custom fallback 을 쓰면 caller 책임.
 * ──────────────────────────────────────────────────────────── */
.axe-error-boundary {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.axe-error-boundary__detail {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: 1.5;
}

.axe-error-boundary__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* ============================================================
 *  StatusBanner — inline dynamic state announcement
 * ============================================================ */
.axe-status-banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-left-width: 4px;
  font-size: var(--text-sm);
  color: var(--text-primary);
  /* output 기본 inline 을 block 으로. */
  width: 100%;
  box-sizing: border-box;
  animation: axe-status-banner-in var(--duration-base) var(--ease-out);
}

@keyframes axe-status-banner-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .axe-status-banner { animation: none; }
}

.axe-status-banner__icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  line-height: 1;
}

.axe-status-banner__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.axe-status-banner__title {
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.axe-status-banner__description {
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

.axe-status-banner__dismiss {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-tertiary);
  cursor: pointer;
  font-size: var(--text-sm);
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  align-self: flex-start;
  transition: color var(--duration-fast) var(--ease-out),
              background var(--duration-fast) var(--ease-out);
}
.axe-status-banner__dismiss:hover {
  color: var(--text-primary);
  background: var(--bg-base);
}
.axe-status-banner__dismiss:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* variants — left accent + soft bg */
.axe-status-banner--saved,
.axe-status-banner--success {
  border-left-color: var(--success);
  background: var(--success-soft);
}
.axe-status-banner--saved   .axe-status-banner__icon,
.axe-status-banner--success .axe-status-banner__icon { color: var(--success); }

.axe-status-banner--splitting,
.axe-status-banner--warning {
  border-left-color: var(--warning);
  background: var(--warning-soft);
}
.axe-status-banner--splitting .axe-status-banner__icon,
.axe-status-banner--warning   .axe-status-banner__icon { color: var(--warning); }
.axe-status-banner--splitting .axe-status-banner__icon {
  animation: axe-status-spin 1.2s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .axe-status-banner--splitting .axe-status-banner__icon { animation: none; }
}

.axe-status-banner--blocked,
.axe-status-banner--error {
  border-left-color: var(--danger);
  background: var(--danger-soft);
}
.axe-status-banner--blocked .axe-status-banner__icon,
.axe-status-banner--error   .axe-status-banner__icon { color: var(--danger); }

.axe-status-banner--info {
  border-left-color: var(--accent);
  background: var(--accent-soft);
}
.axe-status-banner--info .axe-status-banner__icon { color: var(--accent); }

@keyframes axe-status-spin {
  to { transform: rotate(360deg); }
}

/* source: styles/data-views.css */
/* ============================================================
 * @axe/ui — Data Views (Phase 14 Wave 6 — Cortex 흡수)
 *
 * Owns: .axe-tree__*, .axe-timeline__*, .axe-master-detail__*
 * 토큰: --bg-*, --text-*, --border-*, --accent*, --space-*, --radius-*,
 *       --shadow-*, --duration-*, --ease-*, --font-* (모두 src/lib/tokens).
 * 다크/라이트 자동 — CSS var 만 참조.
 *
 * 본 파일은 격리 — components.css 에 통합 전 단계.  소비자는 globals 또는
 * showcase page 에서 직접 import.
 * ============================================================ */

/* ============================================================
 *  Tree — 재귀 트리.  자체 구현 (Radix 비의존).
 *   role="tree" + role="treeitem" + aria-expanded/level/selected 직접 그림.
 * ============================================================ */
.axe-tree {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
  font-size: var(--text-sm);
  color: var(--text-primary);
  outline: none;
}

.axe-tree__item {
  list-style: none;
  position: relative;
  /* item 자체가 focus 받음 (tabIndex roving). */
  outline: none;
}

.axe-tree__item:focus-visible > .axe-tree__row {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: var(--radius-sm);
}

.axe-tree__row {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  width: 100%;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}
.axe-tree__row:hover {
  background: var(--bg-subtle);
  color: var(--text-primary);
}

.axe-tree__item--selected > .axe-tree__row {
  background: var(--accent-soft);
  color: var(--text-primary);
  font-weight: var(--weight-semibold, 600);
}

.axe-tree__item--disabled > .axe-tree__row {
  opacity: 0.5;
  cursor: not-allowed;
}

.axe-tree__chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  flex: 0 0 auto;
  appearance: none;
  background: transparent;
  border: 0;
  padding: 0;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.axe-tree__chevron:hover {
  color: var(--text-primary);
  background: var(--bg-subtle);
}
.axe-tree__chevron--leaf {
  cursor: default;
  /* leaf 도 1.1rem 자리 확보 → 정렬 일관성 */
}

.axe-tree__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
  color: var(--text-tertiary);
}
.axe-tree__item--selected > .axe-tree__row .axe-tree__icon {
  color: var(--accent);
}

.axe-tree__label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: inherit;
  line-height: 1.4;
}

.axe-tree__group {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

/* ============================================================
 *  Timeline — date-grouped activity feed.
 *   좌측 dot (12px) + 수직 line (rail) CSS only.
 *   sticky date header (overflow container 안에서 작동).
 * ============================================================ */
.axe-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  color: var(--text-primary);
  font-size: var(--text-sm);
}

.axe-timeline__group {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.axe-timeline__date-header {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold, 600);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  padding: var(--space-2) 0;
  margin: 0;
  background: color-mix(in oklch, var(--bg-base) 90%, transparent);
  backdrop-filter: saturate(140%) blur(8px);
  -webkit-backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--border-subtle);
}

.axe-timeline--sticky .axe-timeline__date-header {
  position: sticky;
  top: 0;
  z-index: 1;
}

.axe-timeline__items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}

.axe-timeline__item {
  list-style: none;
  display: flex;
  align-items: stretch;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  position: relative;
}

.axe-timeline__rail {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 12px;
  flex: 0 0 12px;
}
/* 수직 line — rail 가운데를 위→아래로 관통. 마지막 item 은 line 짧게. */
.axe-timeline__rail::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  background: var(--border-subtle);
  transform: translateX(-50%);
}
.axe-timeline__item:first-child .axe-timeline__rail::before {
  top: 8px;
}
.axe-timeline__item:last-child .axe-timeline__rail::before {
  bottom: calc(100% - 14px);
}

.axe-timeline__dot {
  position: relative;
  z-index: 1;
  margin-top: 6px;
  width: 10px;
  height: 10px;
  border-radius: 9999px;
  background: var(--bg-base);
  border: 2px solid var(--text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  flex: 0 0 10px;
}

/* variant dots — 토큰 only (Tailwind hex fallback 제거; SSOT 원칙) */
.axe-timeline__item--success .axe-timeline__dot { border-color: var(--success); color: var(--success); }
.axe-timeline__item--warning .axe-timeline__dot { border-color: var(--warning); color: var(--warning); }
.axe-timeline__item--danger  .axe-timeline__dot { border-color: var(--danger);  color: var(--danger);  }
.axe-timeline__item--info    .axe-timeline__dot { border-color: var(--info);    color: var(--info);    }

.axe-timeline__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-bottom: var(--space-2);
}

.axe-timeline__title-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.axe-timeline__title {
  font-weight: var(--weight-medium, 500);
  color: var(--text-primary);
  font-size: var(--text-sm);
  line-height: 1.4;
}

.axe-timeline__time {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.axe-timeline__time--solo {
  display: block;
  margin-bottom: var(--space-1);
}

.axe-timeline__content {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: 1.5;
}

/* compact — icon 없는 dense variant. */
.axe-timeline--compact { gap: var(--space-3); }
.axe-timeline--compact .axe-timeline__item { padding: var(--space-1) 0; }
.axe-timeline--compact .axe-timeline__body { padding-bottom: var(--space-1); }
.axe-timeline--compact .axe-timeline__dot {
  width: 6px;
  height: 6px;
  border-width: 1.5px;
  margin-top: 8px;
}

/* load more / empty / loading */
.axe-timeline__loadmore { list-style: none; display: flex; justify-content: center; padding: var(--space-3) 0; }
.axe-timeline__loadmore-btn {
  appearance: none;
  background: transparent;
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  font: inherit;
  font-size: var(--text-xs);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
}
.axe-timeline__loadmore-btn:hover { background: var(--bg-subtle); color: var(--text-primary); }
.axe-timeline__loadmore-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.axe-timeline__loading { color: var(--text-muted); font-size: var(--text-xs); }
.axe-timeline__empty {
  list-style: none;
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
  padding: var(--space-8) 0;
}

/* ============================================================
 *  MasterDetailLayout — responsive 2-column.
 *   desktop: flex row.  mobile (matchMedia 결과): 한 컬럼만.
 *   isMobile 은 컴포넌트가 JS 로 측정 → .axe-master-detail--mobile class 부여.
 * ============================================================ */
.axe-master-detail {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: var(--space-4);
  width: 100%;
  min-height: 0;
}

.axe-master-detail__master {
  width: var(--axe-md-master-width, 320px);
  flex: 0 0 var(--axe-md-master-width, 320px);
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: auto;
}

.axe-master-detail__detail {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: auto;
}

/* mobile = JS 측정 후 부여되는 modifier */
.axe-master-detail--mobile {
  flex-direction: column;
  gap: 0;
}
.axe-master-detail--mobile .axe-master-detail__master,
.axe-master-detail--mobile .axe-master-detail__detail {
  width: 100%;
  flex: 1 1 auto;
}

.axe-master-detail__master--hidden,
.axe-master-detail__detail--hidden {
  display: none;
}

.axe-master-detail__back {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  appearance: none;
  background: transparent;
  border: 0;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  padding: var(--space-2) var(--space-2);
  margin-bottom: var(--space-2);
  cursor: pointer;
  border-radius: var(--radius-sm);
  align-self: flex-start;
  transition: color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}
.axe-master-detail__back:hover {
  color: var(--text-primary);
  background: var(--bg-subtle);
}
.axe-master-detail__back:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.axe-master-detail__back-arrow {
  font-size: var(--text-base);
  line-height: 1;
}

.axe-master-detail__empty {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
  padding: var(--space-8);
  flex: 1 1 auto;
}

/* ============================================================
 *  prefers-reduced-motion — 모든 transition/animation 비활성화
 * ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .axe-tree__row,
  .axe-tree__chevron,
  .axe-timeline__loadmore-btn,
  .axe-master-detail__back {
    transition: none !important;
    animation: none !important;
  }
}

/* source: styles/chat-ext.css */
/* ============================================================
 * @axe/ui — Phase 14 Wave 6 — Chat extensions + Cortex 흡수
 *
 * Owns:
 *   .axe-message-with-sources__*  (MessageWithSources)
 *   .axe-typing-indicator__*      (TypingIndicator)
 *   .axe-responsive-tabs__*       (ResponsiveTabs)
 *
 * 토큰: --bg-*, --text-*, --border-*, --accent*, --space-*, --radius-*,
 *       --duration-*, --ease-*, --success/--warning/--danger (-soft).
 * 다크/라이트 자동 — CSS var 만 참조.
 *
 * 페이지 격리: showcase 페이지 (app/ui/v2/chat-ext) 에서 직접 import.
 * components.css 통합은 Wave 안정화 후.
 * ============================================================ */

/* ============================================================
 *  MessageWithSources — MessageBubble 확장
 * ============================================================ */
.axe-message-with-sources .axe-message__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.axe-message-with-sources__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

.axe-message-with-sources__body-text {
  flex: 1;
  min-width: 0;
  white-space: pre-wrap;
  word-break: break-word;
}

.axe-message-with-sources__head-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-shrink: 0;
}

.axe-message-with-sources__confidence {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  letter-spacing: var(--tracking-wide);
}
.axe-message-with-sources__confidence--low {
  background: var(--danger-soft);
  color: var(--danger);
}
.axe-message-with-sources__confidence--med {
  background: var(--warning-soft);
  color: var(--warning);
}
.axe-message-with-sources__confidence--high {
  background: var(--success-soft);
  color: var(--success);
}

.axe-message-with-sources__copy {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-tertiary);
  font-family: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  transition: color var(--duration-fast) var(--ease-out),
              background var(--duration-fast) var(--ease-out);
}
.axe-message-with-sources__copy:hover {
  color: var(--text-primary);
  background: var(--bg-subtle);
}
.axe-message-with-sources__copy:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* sources <details> */
.axe-message-with-sources__sources {
  border-top: 1px solid var(--border-subtle);
  padding-top: var(--space-3);
}
.axe-message-with-sources__sources-summary {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  cursor: pointer;
  user-select: none;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px 0;
}
.axe-message-with-sources__sources-summary::-webkit-details-marker {
  display: none;
}
.axe-message-with-sources__sources-summary::before {
  content: "▸";
  color: var(--text-muted);
  font-size: 0.7em;
  transition: transform var(--duration-fast) var(--ease-out);
  display: inline-block;
}
.axe-message-with-sources__sources[open] .axe-message-with-sources__sources-summary::before {
  transform: rotate(90deg);
}
.axe-message-with-sources__sources-summary:hover {
  color: var(--text-secondary);
}

.axe-message-with-sources__sources-list {
  margin: var(--space-2) 0 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.axe-message-with-sources__source {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--space-2);
  align-items: baseline;
  font-size: var(--text-xs);
  padding: var(--space-2);
  background: var(--bg-subtle);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-subtle);
}

.axe-message-with-sources__source-type {
  grid-column: 1;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-muted);
  background: var(--bg-base);
  padding: 1px 5px;
  border-radius: var(--radius-xs);
}

.axe-message-with-sources__source-title {
  grid-column: 2;
  color: var(--text-primary);
  font-weight: var(--weight-medium);
  text-decoration: none;
}
a.axe-message-with-sources__source-title:hover {
  color: var(--accent);
  text-decoration: underline;
}

.axe-message-with-sources__source-snippet {
  grid-column: 1 / -1;
  color: var(--text-tertiary);
  font-style: italic;
  white-space: pre-wrap;
}

.axe-message-with-sources__source-conf {
  grid-column: 3;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  padding: 1px 5px;
  border-radius: var(--radius-xs);
}
.axe-message-with-sources__source-conf--low  { background: var(--danger-soft); color: var(--danger); }
.axe-message-with-sources__source-conf--med  { background: var(--warning-soft); color: var(--warning); }
.axe-message-with-sources__source-conf--high { background: var(--success-soft); color: var(--success); }

/* footer / tokens metabar */
.axe-message-with-sources__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-top: var(--space-2);
  border-top: 1px dashed var(--border-subtle);
  flex-wrap: wrap;
}
.axe-message-with-sources__tokens {
  display: flex;
  gap: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}
.axe-message-with-sources__token {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
}
.axe-message-with-sources__token-label {
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  font-size: 0.7rem;
}
.axe-message-with-sources__token-val {
  color: var(--text-secondary);
  font-weight: var(--weight-medium);
}

/* ============================================================
 *  TypingIndicator — 3-dot wave
 * ============================================================ */
.axe-typing-indicator {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: var(--space-2) var(--space-3);
}

.axe-typing-indicator--sm { --axe-typing-dot: 5px; gap: 3px; padding: var(--space-1) var(--space-2); }
.axe-typing-indicator--md { --axe-typing-dot: 7px; gap: 4px; }
.axe-typing-indicator--lg { --axe-typing-dot: 10px; gap: 5px; padding: var(--space-3) var(--space-4); }

.axe-typing-indicator__dot {
  display: inline-block;
  width: var(--axe-typing-dot, 7px);
  height: var(--axe-typing-dot, 7px);
  border-radius: var(--radius-full);
  background: var(--text-tertiary);
  opacity: 0.4;
  animation: axe-typing-wave 1.2s ease-in-out infinite;
}

@keyframes axe-typing-wave {
  0%, 60%, 100% {
    opacity: 0.3;
    transform: translateY(0);
  }
  30% {
    opacity: 1;
    transform: translateY(-3px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .axe-typing-indicator__dot {
    animation: none;
    opacity: 0.5;
  }
}

/* ============================================================
 *  ResponsiveTabs — desktop pills + mobile bottom-nav
 * ============================================================ */
.axe-responsive-tabs {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* ---------- Desktop pills ---------- */
.axe-responsive-tabs__pills {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  padding: 4px;
  background: var(--bg-subtle);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-subtle);
  width: fit-content;
  max-width: 100%;
}

.axe-responsive-tabs__pill {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-secondary);
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  padding: 6px 14px;
  border-radius: var(--radius-md);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  white-space: nowrap;
  transition: color var(--duration-fast) var(--ease-out),
              background var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}
.axe-responsive-tabs__pill:hover {
  color: var(--text-primary);
}
.axe-responsive-tabs__pill:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.axe-responsive-tabs__pill[data-state="active"] {
  background: var(--bg-base);
  color: var(--text-primary);
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.06), 0 0 0 1px var(--border-default);
}
.axe-responsive-tabs__pill[data-disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

.axe-responsive-tabs__pill-icon {
  display: inline-flex;
  align-items: center;
  font-size: 1.1em;
}

.axe-responsive-tabs__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--accent-fg);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: var(--weight-semibold);
  line-height: 1;
}

.axe-responsive-tabs__content {
  flex: 1;
  min-height: 0;
}

/* ---------- Mobile bottom-nav ---------- */
.axe-responsive-tabs--mobile {
  position: relative;
  /* 컨텐츠가 bottom-nav 뒤로 숨지 않게. */
}
.axe-responsive-tabs--mobile .axe-responsive-tabs__content {
  /* 56px nav + safe-area. */
  padding-bottom: calc(56px + var(--axe-safe-bottom, 0px) + var(--space-3));
}

.axe-responsive-tabs__bottom-nav {
  display: flex;
  align-items: stretch;
  justify-content: space-around;
  background: var(--bg-base);
  border-top: 1px solid var(--border-subtle);
  z-index: 50;
}

.axe-responsive-tabs__bottom-nav--fixed {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
}

.axe-responsive-tabs__bottom-btn {
  flex: 1;
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--text-tertiary);
  font-family: inherit;
  font-size: 0.7rem;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: var(--space-2) var(--space-1);
  min-height: 56px;
  position: relative;
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-responsive-tabs__bottom-btn:hover {
  color: var(--text-secondary);
}
.axe-responsive-tabs__bottom-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.axe-responsive-tabs__bottom-btn--active {
  color: var(--accent);
}
.axe-responsive-tabs__bottom-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.axe-responsive-tabs__bottom-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  line-height: 1;
}

.axe-responsive-tabs__bottom-label {
  font-size: 0.7rem;
  line-height: 1.1;
  text-align: center;
}

.axe-responsive-tabs__bottom-btn .axe-responsive-tabs__badge {
  position: absolute;
  top: 6px;
  right: calc(50% - 18px);
  transform: translateX(50%);
}

/* source: styles/composites.css */
/* ============================================================
 * AXE Labs — composites (Phase 14 Wave 6)
 *
 * inline 반복 패턴 + Blueprint splitter 흡수:
 *   - Code (inline 토큰)
 *   - Section (anchor + scroll-margin)
 *   - Hero
 *   - Footer
 *   - Splitter (2-pane resizable + a11y)
 *   - Callout accent modifiers (left-bar / both / none / icon)
 *
 * 본 파일은 별도 — 메인 components.css 는 통합자가 직접 @import 추가.
 * ============================================================ */

/* ------- Code (inline) -------
 *  Kbd 와 자매. <CodeBlock> 의 블록 + copy 버튼과 의미 분리.
 *  기존 .axe-code-inline 정의가 components.css 에 있으면 거기가 우선 —
 *  본 파일은 variant/size modifier 만 추가.
 */
.axe-code-inline {
  /* 기존 정의가 components.css 에 없을 때를 위한 baseline */
  font-family: var(--font-mono);
  font-size: 0.9em;
  padding: 0.1em 0.35em;
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  color: var(--text-primary);
  white-space: nowrap;
}
.axe-code-inline--muted {
  color: var(--text-secondary);
  background: var(--bg-base);
  border-color: var(--border-subtle);
}
.axe-code-inline--accent {
  color: var(--accent);
  background: color-mix(in oklch, var(--accent) 10%, transparent);
  border-color: color-mix(in oklch, var(--accent) 30%, transparent);
}
.axe-code-inline--size-sm {
  font-size: 0.8em;
  padding: 0.05em 0.3em;
}

/* ------- Section ------- */
.axe-section {
  scroll-margin-top: 5rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  min-width: 0;
  max-width: 100%;
}
.axe-section--center {
  text-align: center;
  align-items: center;
}
.axe-section__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
  max-width: 100%;
}
.axe-section--center .axe-section__header {
  align-items: center;
}
.axe-section__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-widest); /* 12px uppercase 는 0.08em 이 표준대 */
  text-transform: uppercase;
  font-weight: var(--weight-medium);
  color: var(--text-tertiary);
}
/* eyebrow 앞 브랜드 점 — AXE wine을 작은 identity signal로만 사용. */
.axe-section__eyebrow::before,
.axe-hero__eyebrow::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--border-strong);
  flex-shrink: 0;
}
.axe-hero__eyebrow::before {
  background: var(--brand-claret);
}
.axe-section__title {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-heading);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  margin: 0;
}
.axe-section__subtitle {
  font-size: var(--text-sm);
  line-height: var(--leading-body);
  color: var(--text-secondary); /* tertiary → secondary: 다크 모드 AA 확보 */
  margin: 0;
  max-width: 56ch;
}
.axe-section--center .axe-section__subtitle {
  margin-inline: auto;
}
/* 캔버스 보조 고지 한 줄 — 목록/본문 **아래**에 붙는 사실 고지("최근 50건만
 * 표시" 류). `__subtitle` 과 자매이되 자리가 반대다: 부제는 헤더 안에서 섹션을
 * 예고하고, 이것은 본문 뒤에서 방금 보여준 것의 범위를 밝힌다. 그래서 서체 축
 * (text-sm · leading-body · 56ch 측정)은 부제와 같고 색만 한 단 낮춘다
 * (secondary → muted) — 예고는 읽히라고 있지만 고지는 본문을 다 읽은 뒤 눈에
 * 들어오면 된다.
 *
 * 세로 리듬은 `__header` 의 내부 gap 과 같은 축(`--space-2`)이다 — 고지는 자기
 * 위 블록에 붙어 있어야 그 블록에 대한 말로 읽힌다. `.axe-section` 의 직계 자식으로
 * 서면 그 자리를 flex `gap: var(--space-5)` 가 이미 소유하므로 **gap 을 상쇄해**
 * 같은 8px 로 붙인다(`--space-2` − `--space-5` = −16px, flex 는 음수 margin 을
 * 존중한다). margin 을 0 으로 눕히면 gap 만 남아 24px 이 되어, 고지가 본문에서
 * 떨어져 나와 다음 섹션 것처럼 읽힌다 — 두 갈래(래퍼 안 · 직계 자식)가 같은
 * 부착 간격을 내야 자리가 하나다. */
.axe-section__note {
  font-size: var(--text-sm);
  line-height: var(--leading-body);
  color: var(--text-muted);
  margin: var(--space-2) 0 0;
  max-width: 56ch;
}
.axe-section > .axe-section__note:not(:first-child) {
  margin-block-start: calc(var(--space-2) - var(--space-5));
}
.axe-section--center .axe-section__note {
  margin-inline: auto;
}
.axe-section__body {
  display: block;
  min-width: 0;
  max-width: 100%;
}

/* ------- Hero ------- */
.axe-hero {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-7);
  padding: var(--space-7) 0;
  align-items: center;
}
.axe-hero--with-image {
  grid-template-columns: 1fr;
}
@media (min-width: 768px) {
  .axe-hero--with-image {
    grid-template-columns: 1.1fr 1fr;
  }
}
.axe-hero--center {
  text-align: center;
}
.axe-hero--center .axe-hero__content {
  align-items: center;
  margin-inline: auto;
}
.axe-hero__content {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 42rem;
}
.axe-hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  font-weight: var(--weight-medium);
  color: var(--text-tertiary);
}
.axe-hero__title {
  font-family: var(--font-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-heading);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  margin: 0;
}
.axe-hero--size-md .axe-hero__title { font-size: var(--text-3xl); }
.axe-hero--size-lg .axe-hero__title { font-size: var(--text-4xl); }
.axe-hero--size-xl .axe-hero__title { font-size: var(--text-5xl); }
/* display 티어 — 랜딩/마케팅 hero 전용 (32~80px fluid). 기존 md/lg/xl 불변. */
.axe-hero--size-display .axe-hero__title {
  font-size: var(--text-display-md);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
}
.axe-hero--size-display .axe-hero__content {
  max-width: 52rem;
}
.axe-hero--size-display .axe-hero__subtitle {
  font-size: var(--text-xl);
  max-width: 40rem;
}

/* 브랜드 hero — 라이트/다크 공통 wine 워시 + display 페이스(Clash).
 * 배경은 radial wash 1장 (paint 1회, 스크롤 비용 0). */
.axe-hero--brand {
  position: relative;
}
.axe-hero--brand::before {
  content: "";
  position: absolute;
  inset: calc(-1 * var(--space-7)) calc(-1 * var(--space-6));
  background:
    radial-gradient(
      90% 65% at 50% -10%,
      color-mix(in srgb, var(--brand-claret) 10%, transparent),
      transparent 70%
    );
  pointer-events: none;
}
/* 좁은 폭 — 우측 -32px bleed 가 body 가로 스크롤 +16px 을 만들던 원인
 * (2026-06-10 모바일 감사). 글로우는 좌우 bleed 없이 충분. */
@media (max-width: 767px) {
  .axe-hero--brand::before {
    inset: calc(-1 * var(--space-7)) 0;
  }
}
.axe-hero--brand .axe-hero__content {
  position: relative;
}
.axe-hero--brand .axe-hero__title {
  font-family: var(--font-clash); /* Latin=Clash, 한글=Pretendard 폴백 (의도) */
}
/* hero 타이틀 안 키워드 강조 — <em> 1개 규칙 (이탤릭 아님, 브랜드 색) */
.axe-hero--brand .axe-hero__title em {
  font-style: normal;
  color: var(--brand-claret);
}
.axe-hero__subtitle {
  font-size: var(--text-lg);
  line-height: var(--leading-body);
  color: var(--text-secondary);
  margin: 0;
  max-width: 36rem;
}
.axe-hero--center .axe-hero__subtitle {
  margin-inline: auto;
}
.axe-hero__badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.axe-hero--center .axe-hero__badges {
  justify-content: center;
}
.axe-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-2);
}
.axe-hero--center .axe-hero__actions {
  justify-content: center;
}
.axe-hero__image {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
}

/* ------- Footer ------- */
.axe-footer {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-7) 0 var(--space-5);
  border-top: 1px solid var(--border-subtle);
  color: var(--text-tertiary);
  font-size: var(--text-sm);
}
.axe-footer__top {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
}
@media (min-width: 768px) {
  .axe-footer__top {
    grid-template-columns: minmax(160px, 1fr) 3fr;
  }
}
.axe-footer__logo {
  display: flex;
  align-items: flex-start;
}
.axe-footer__columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--space-5);
}
.axe-footer__column {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.axe-footer__column-title {
  font-size: var(--text-xs);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-secondary);
  font-weight: var(--weight-medium);
}
.axe-footer__column-items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.axe-footer__link {
  color: var(--text-tertiary);
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-footer__link:hover {
  color: var(--text-primary);
}
.axe-footer__bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}
.axe-footer__bottom-left {
  flex: 1;
  min-width: 0;
}
.axe-footer__social {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.axe-footer__social-link {
  color: var(--text-tertiary);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-md);
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-footer__social-link:hover {
  color: var(--text-primary);
  background: var(--bg-subtle);
}

/* ------- Splitter ------- */
.axe-splitter {
  display: flex;
  width: 100%;
  height: 100%;
  min-height: 0;
  min-width: 0;
}
.axe-splitter--horizontal {
  flex-direction: row;
}
.axe-splitter--vertical {
  flex-direction: column;
}
.axe-splitter__pane {
  min-width: 0;
  min-height: 0;
  overflow: auto;
}
.axe-splitter__pane--second {
  flex: 1 1 auto;
}
.axe-splitter__handle {
  flex-shrink: 0;
  background: transparent;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--duration-fast) var(--ease-out);
  touch-action: none;
}
/* visual 은 6px 유지, hit-area 는 ::before 로 24px 확장 (WCAG 2.5.5 target size).
 * 결과적으로 마우스/터치 클릭 영역이 늘어나 모바일 사용성 보장. */
.axe-splitter--horizontal > .axe-splitter__handle {
  width: 6px;
  cursor: col-resize;
}
.axe-splitter--vertical > .axe-splitter__handle {
  height: 6px;
  cursor: row-resize;
}
.axe-splitter__handle::before {
  content: "";
  position: absolute;
  inset: -10px;   /* 6 + 2*10 = 26px hit-area */
}
.axe-splitter__handle:hover,
.axe-splitter__handle:focus-visible {
  background: color-mix(in oklch, var(--accent) 25%, transparent);
  outline: none;
}
.axe-splitter__handle:focus-visible {
  background: color-mix(in oklch, var(--accent) 40%, transparent);
}
.axe-splitter__handle-bar {
  background: var(--border-subtle);
  border-radius: 2px;
  transition: background var(--duration-fast) var(--ease-out);
}
.axe-splitter--horizontal .axe-splitter__handle-bar {
  width: 2px;
  height: 36px;
}
.axe-splitter--vertical .axe-splitter__handle-bar {
  height: 2px;
  width: 36px;
}
.axe-splitter__handle:hover .axe-splitter__handle-bar,
.axe-splitter__handle:focus-visible .axe-splitter__handle-bar {
  background: var(--accent);
}
@media (prefers-reduced-motion: reduce) {
  .axe-splitter__handle,
  .axe-splitter__handle-bar {
    transition: none;
  }
}

/* ------- Callout accent modifiers (확장) -------
 *  기본 .axe-callout--<variant> 의 컬러 트림은 components.css 에서 정의됨.
 *  본 파일은 그 위에 얹는 "accent 방식" 만 추가.
 */
.axe-callout--accent-icon {
  /* default — 기존 동작. 추가 스타일 없음. */
}
.axe-callout--accent-left-bar,
.axe-callout--accent-both {
  border-left-width: 4px;
}
.axe-callout--accent-none {
  /* 색 트림 제거 — 배경/텍스트만 살림. */
  border-color: var(--border-subtle);
}
.axe-callout--accent-none.axe-callout--info,
.axe-callout--accent-none.axe-callout--success,
.axe-callout--accent-none.axe-callout--warning,
.axe-callout--accent-none.axe-callout--danger {
  border-color: var(--border-subtle);
}

/* ------- Reveal (진입 모션 vocabulary) -------
 * CSS-only — maud/jinja 도 class + style="--reveal-i: N" 만으로 동일 모션.
 * scroll-driven (animation-timeline: view()) 지원 브라우저는 스크롤 진입 시,
 * 미지원은 로드 시 1회 재생. JS 0.
 * reduced-motion 은 reset.css 전역 클램프가 자동 무효화. */
@keyframes axe-reveal-up {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.axe-reveal {
  animation: axe-reveal-up var(--duration-slower) var(--ease-out) both;
  animation-delay: calc(var(--reveal-i, 0) * 60ms); /* stagger: --reveal-i 부여 */
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .axe-reveal {
      animation-timeline: view();
      animation-range: entry 0% entry 40%;
      animation-delay: 0s; /* scroll-driven 에선 stagger 대신 진입 위치가 타이밍 */
      animation-duration: auto;
    }
  }
}
/* progress-기반 timeline 은 reset.css 의 duration 클램프가 안 먹는다
 * (시간이 아니라 스크롤 진행도) — reduced-motion 은 명시적으로 끔. */
@media (prefers-reduced-motion: reduce) {
  .axe-reveal {
    animation: none;
  }
}

/* ------- content-visibility 유틸 -------
 * 긴 단일 페이지의 below-fold 섹션 lazy-layout.
 * ⚠ 사용 제한 (2026-06-10 리뷰): ① #anchor 타깃 섹션에 쓰지 말 것 —
 * intrinsic-size 추정 오차 + smooth scroll 이 결합하면 anchor 착지가 어긋남.
 * ② position:fixed 자손 (CommandPalette·비포털 오버레이) 이 있는 섹션 금지 —
 * containment 가 fixed 의 containing block 이 되어 클리핑됨. */
.axe-cv-auto {
  content-visibility: auto;
  contain-intrinsic-size: auto 720px;
}

/* source: styles/document.css */
/* ============================================================
 * @axe/ui — Document / print templates (Phase 17, D-ui-3 Phase 2)
 *
 * AXE 발신 문서 (IC Memo · LP letter 등) 를 가로(landscape)·세로(portrait)
 * 모두 지원하는 CSS-class HTML 템플릿. "Tailwind 0" — 100% `.axe-doc*`
 * 클래스 + CSS var → React 없이 Python(jinja)/Rust(maud) 가 동일 markup 재사용.
 *
 * Owns: .axe-doc-stage, .axe-doc, .axe-doc__* (masthead/title/meta/section/
 *       kpi/callout/table/signoff/footer), 인쇄 유틸 (.axe-doc__pagebreak 등),
 *       표 variants (.axe-doc__table--financial/--compact/--keep/--compare,
 *       .axe-doc__row--*, 셀 유틸 .axe-doc__ctr/__neg/__pos/__fn/__cellbar),
 *       데이터 비주얼 (.axe-doc-viz*, .axe-doc-diagram* — Phase 18 Track B).
 *
 * 설계 원칙:
 *  1. 테마 독립 — 문서는 light/dark 와 무관하게 동일 (흰 종이·먹 잉크).
 *     `.axe-doc` 가 자체 `--doc-*` 팔레트를 깔아 전역 테마 토큰을 덮음.
 *     accent 는 흰 종이용 `--brand-claret-print` 추종 (rebrand 시 별도 교체).
 *  2. 스코프 @page — named page (`page:` property) 로만 size/margin 지정 →
 *     `.axe-doc` 없는 일반 페이지 인쇄에는 영향 0 (전역 bare @page 금지).
 *  3. pt 단위 본문 — 인쇄 충실도. 화면에서도 mm 종이 위 pt 글자로 동일 비율.
 *  4. 화면 미리보기 = 회색 backdrop 위 mm 폭 종이 + 그림자. @media print 에서
 *     backdrop/그림자 제거하고 @page margin 이 여백을 인계.
 *
 * 토큰: --font-sans, --font-display, --brand-claret-print, --space-*, --radius-*
 *       (src/lib/tokens). 색은 --doc-* 로 재정의 (테마 무관 고정).
 * 렌더: 브라우저 "인쇄→PDF" (named @page size 인식) + md-to-pdf 파이프라인
 *       (Puppeteer landscape 옵션을 orientation 에 맞춰 셋 — 렌더 측 책임).
 * ============================================================ */

/* ------------------------------------------------------------
 *  Named @page — 스코프됨 (page: property 로 선택, 전역 미적용)
 *  A4 = 210 × 297 mm. 여백: 세로 22/20, 가로 16/22 (mm, T/B · L/R).
 * ------------------------------------------------------------ */
@page axe-doc-portrait {
  size: A4 portrait;
  margin: 22mm 20mm;
}
@page axe-doc-landscape {
  size: A4 landscape;
  margin: 16mm 22mm;
}

/* ------------------------------------------------------------
 *  Stage — 화면 전용 회색 backdrop (showcase/preview 환경).
 *  종이를 가운데 띄우고 스크롤. 인쇄 시 사라짐.
 * ------------------------------------------------------------ */
.axe-doc-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-7) var(--space-5);
  background: var(--gray-3, #efefee);
  min-height: 100%;
}

/* ------------------------------------------------------------
 *  Document palette — printed paper and Gate's document-adjacent previews share
 *  one theme-independent palette. Gate keeps its application chrome theme while
 *  iframe/stamp/print surfaces can resolve the same paper tokens outside .axe-doc.
 * ------------------------------------------------------------ */
.axe-doc,
.axe-pattern-gate-app {
  --doc-paper: #ffffff;
  --doc-ink: #16130f; /* 본문 — 따뜻한 먹색 */
}

/* ------------------------------------------------------------
 *  .axe-doc — 종이 (root).
 * ------------------------------------------------------------ */
.axe-doc {
  color-scheme: light;
  --doc-ink-2: #423a2b; /* 보조 텍스트 */
  --doc-muted: #756a52; /* 라벨 · 캡션 */
  --doc-rule: #ddd6c5; /* 헤어라인 */
  --doc-rule-strong: #b1a78f; /* 강조 구분선 */
  --doc-band: #f6f3ec; /* 옅은 띠 배경 (meta/kpi) */
  --doc-accent: var(--brand-claret-print, #821f3b); /* 흰 종이용 AXE 와인 시그니처 */
  --doc-accent-ink: #6b1830;
  --doc-accent-soft: rgb(130 31 59 / 0.06);

  /* 인쇄/화면 공통 본문 타이포 — pt 기준 */
  font-family: var(--font-sans);
  font-size: 10.5pt;
  line-height: 1.55;
  color: var(--doc-ink);
  background: var(--doc-paper);
  text-align: left;
  word-break: keep-all;
  overflow-wrap: break-word;

  /* 화면 종이 geometry (세로 기본) — mm 폭 + 그림자 */
  box-sizing: border-box;
  width: 210mm;
  min-height: 297mm;
  padding: 22mm 20mm;
  margin-inline: auto;
  box-shadow: 0 6px 28px rgb(31 26 19 / 0.18);

  /* 기본 페이지 = 세로 (landscape modifier 가 override) */
  page: axe-doc-portrait;
}

/* 가로 modifier — 화면 geometry + named page 교체 */
.axe-doc--landscape {
  width: 297mm;
  min-height: 210mm;
  padding: 16mm 22mm;
  page: axe-doc-landscape;
}
/* 세로 modifier (명시) — 기본과 동일하나 markup 가독성용 */
.axe-doc--portrait {
  width: 210mm;
  min-height: 297mm;
  padding: 22mm 20mm;
  page: axe-doc-portrait;
}

/* ------------------------------------------------------------
 *  Masthead / letterhead — 상단 브랜드 밴드
 * ------------------------------------------------------------ */
.axe-doc__masthead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: 8pt;
  border-bottom: 1.5pt solid var(--doc-accent);
  margin-bottom: 16pt;
}
.axe-doc__wordmark {
  /* 브랜드 워드마크 = Clash Display (display 페이스). 클래스에 직접 박는다 —
   * 문서별 인라인 style(var(--font-clash)) 은 layer 뷰어의 opaque sandbox iframe
   * 에서 적용되지 않아(클래스 규칙만 먹음) Pretendard 로 폴백했었다. */
  font-family: var(--font-brand, var(--font-clash));
  font-size: 13pt;
  /* 두께·트래킹은 .axe-topnav__brand(앱 nav 워드마크) 와 동일 톤 — medium + 살짝
   * 타이트. 과거 700 + 0.14em(넓은 letterhead 트래킹)은 nav 워드마크와 안 맞았음. */
  font-weight: var(--weight-medium);
  letter-spacing: -0.01em;
  /* 워드마크는 작성된 케이스 그대로 렌더 (예: "AXE·Corporation").
   * 과거 letterhead 전체 대문자화는 mixed-case 브랜드명을 강제 변형했음. */
  text-transform: none;
  /* 워드마크 = AXE 와인(버건디) 시그니처 — 마스트헤드 보더·confidential 과 동일 강조색. */
  color: var(--doc-accent);
  line-height: 1;
}
.axe-doc__wordmark-accent {
  color: var(--doc-accent);
}
.axe-doc__doctype {
  font-size: 8pt;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--doc-muted);
  text-align: right;
}

/* Confidential 태그 — masthead 우측 또는 단독 */
.axe-doc__confidential {
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--doc-accent);
}

/* ------------------------------------------------------------
 *  Title block
 * ------------------------------------------------------------ */
.axe-doc__title {
  font-family: var(--font-display);
  font-size: 22pt;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--doc-ink);
  margin: 0 0 4pt;
}
.axe-doc__subtitle {
  font-size: 12pt;
  font-weight: 400;
  line-height: 1.35;
  color: var(--doc-ink-2);
  margin: 0 0 14pt;
}

/* Meta grid — Date / Author / Recipient 등 라벨·값 쌍 */
.axe-doc__meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 5pt 18pt;
  padding: 9pt 12pt;
  background: var(--doc-band);
  border: 0.75pt solid var(--doc-rule);
  border-radius: var(--radius-sm);
  margin-bottom: 16pt;
}
.axe-doc__meta--3col {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.axe-doc__meta-item {
  display: flex;
  flex-direction: column;
  gap: 1pt;
}
.axe-doc__meta-label {
  font-size: 7pt;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--doc-muted);
}
.axe-doc__meta-value {
  font-size: 9.5pt;
  color: var(--doc-ink);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------
 *  Section
 * ------------------------------------------------------------ */
.axe-doc__section {
  margin-top: 16pt;
}
.axe-doc__section-title {
  font-family: var(--font-display);
  font-size: 12.5pt;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--doc-ink);
  padding-bottom: 3pt;
  margin: 0 0 8pt;
  border-bottom: 0.75pt solid var(--doc-rule-strong);
  break-after: avoid;
}
.axe-doc__section-title--accent {
  color: var(--doc-accent);
  border-bottom-color: var(--doc-accent);
}
/* 번호 매기는 섹션 (CSS counter) — .axe-doc__body 에 .axe-doc__body--numbered */
.axe-doc__body--numbered {
  counter-reset: axe-doc-sec;
}
.axe-doc__body--numbered .axe-doc__section-title::before {
  counter-increment: axe-doc-sec;
  content: counter(axe-doc-sec) ". ";
  color: var(--doc-accent);
}

/* ------------------------------------------------------------
 *  Body prose — h/p/list/quote/link (jinja 본문이 그대로 흘리는 태그)
 * ------------------------------------------------------------ */
.axe-doc__body {
  font-size: 10.5pt;
  line-height: 1.55;
  color: var(--doc-ink);
}
.axe-doc__body > :first-child {
  margin-top: 0;
}
.axe-doc__body h2 {
  font-family: var(--font-display);
  font-size: 12.5pt;
  font-weight: 700;
  margin: 16pt 0 7pt;
  break-after: avoid;
}
.axe-doc__body h3 {
  font-size: 11pt;
  font-weight: 700;
  color: var(--doc-ink);
  margin: 12pt 0 5pt;
  break-after: avoid;
}
.axe-doc__body h4 {
  font-size: 10pt;
  font-weight: 700;
  color: var(--doc-ink-2);
  letter-spacing: 0.01em;
  margin: 10pt 0 4pt;
  break-after: avoid;
}
.axe-doc__body p {
  margin: 0 0 7pt;
}
.axe-doc__body ul,
.axe-doc__body ol {
  margin: 0 0 7pt;
  padding-left: 16pt;
}
.axe-doc__body li {
  margin-bottom: 2.5pt;
}
.axe-doc__body li::marker {
  color: var(--doc-muted);
}
/* 본문·콜아웃 링크 — AXE 와인색 + 분명한(은은) 밑줄로 "링크임"을 명확히.
 * 과거 0.06 알파 보더는 사실상 안 보여 링크 식별 불가였음(시퍼런 파랑은 지양). */
.axe-doc__body a,
.axe-doc__callout-body a {
  color: var(--doc-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.16em;
  text-decoration-color: rgb(130 31 59 / 0.5);
  text-decoration-skip-ink: auto;
}
.axe-doc__body a:hover,
.axe-doc__callout-body a:hover {
  color: var(--doc-accent-ink);
  text-decoration-color: var(--doc-accent);
}
.axe-doc__body strong {
  font-weight: 700;
  color: var(--doc-ink);
}
.axe-doc__body blockquote {
  margin: 8pt 0;
  padding: 4pt 0 4pt 12pt;
  border-left: 2pt solid var(--doc-rule-strong);
  color: var(--doc-ink-2);
  font-style: italic;
}
.axe-doc__body code {
  font-family: var(--font-mono);
  font-size: 9pt;
  background: var(--doc-band);
  padding: 0.5pt 3pt;
  border-radius: var(--radius-xs);
}
.axe-doc__rule {
  border: none;
  border-top: 0.75pt solid var(--doc-rule);
  margin: 12pt 0;
}

/* ------------------------------------------------------------
 *  KPI tiles — Pre/Post money, IRR, ownership 등 수치 강조
 * ------------------------------------------------------------ */
.axe-doc__kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110pt, 1fr));
  gap: 8pt;
  margin: 12pt 0;
}
.axe-doc__kpi {
  padding: 8pt 10pt;
  background: var(--doc-band);
  border: 0.75pt solid var(--doc-rule);
  border-radius: var(--radius-sm);
  break-inside: avoid;
}
.axe-doc__kpi-label {
  font-size: 7pt;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--doc-muted);
  margin-bottom: 3pt;
}
.axe-doc__kpi-value {
  font-size: 15pt;
  font-weight: 700;
  line-height: 1.05;
  color: var(--doc-ink);
  font-variant-numeric: tabular-nums;
}
.axe-doc__kpi-sub {
  font-size: 8pt;
  color: var(--doc-muted);
  margin-top: 2pt;
}
.axe-doc__kpi--accent {
  border-color: var(--doc-accent);
}
.axe-doc__kpi--accent .axe-doc__kpi-value {
  color: var(--doc-accent);
}

/* ------------------------------------------------------------
 *  Callout / Recommendation box — Go / Conditional / Pass
 * ------------------------------------------------------------ */
.axe-doc__callout {
  display: flex;
  flex-direction: column;
  gap: 3pt;
  padding: 9pt 12pt 9pt 14pt;
  background: var(--doc-accent-soft);
  border-left: 3pt solid var(--doc-accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  margin: 12pt 0;
  break-inside: avoid;
}
.axe-doc__callout-label {
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--doc-accent);
}
.axe-doc__callout-title {
  font-size: 12pt;
  font-weight: 700;
  color: var(--doc-ink);
}
.axe-doc__callout-body {
  font-size: 9.5pt;
  color: var(--doc-ink-2);
}
/* 의미 variant — 인쇄 시 배경 보장 (print-color-adjust 아래) */
.axe-doc__callout--go {
  background: #e9f6ec;
  border-left-color: #2b7a3f;
}
.axe-doc__callout--go .axe-doc__callout-label {
  color: #2b7a3f;
}
.axe-doc__callout--conditional {
  background: #fbf0e0;
  border-left-color: #b8651a;
}
.axe-doc__callout--conditional .axe-doc__callout-label {
  color: #b8651a;
}
.axe-doc__callout--pass {
  background: #fbe7e2;
  border-left-color: #c4321f;
}
.axe-doc__callout--pass .axe-doc__callout-label {
  color: #c4321f;
}

/* ------------------------------------------------------------
 *  Table — formal
 * ------------------------------------------------------------ */
.axe-doc__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 9pt;
  margin: 10pt 0;
  font-variant-numeric: tabular-nums;
}
.axe-doc__table caption {
  caption-side: top;
  text-align: left;
  font-size: 8pt;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--doc-muted);
  margin-bottom: 4pt;
}
.axe-doc__table th {
  text-align: left;
  font-weight: 700;
  color: var(--doc-ink);
  padding: 5pt 8pt;
  border-bottom: 1pt solid var(--doc-rule-strong);
  vertical-align: bottom;
}
.axe-doc__table td {
  padding: 5pt 8pt;
  border-bottom: 0.5pt solid var(--doc-rule);
  color: var(--doc-ink-2);
  vertical-align: top;
}
.axe-doc__table tr {
  break-inside: avoid;
}
.axe-doc__table--zebra tbody tr:nth-child(even) {
  background: var(--doc-band);
}
.axe-doc__table .axe-doc__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------
 *  Signature / sign-off block
 * ------------------------------------------------------------ */
.axe-doc__signoff {
  margin-top: 24pt;
  display: flex;
  flex-wrap: wrap;
  gap: 24pt;
  break-inside: avoid;
}
.axe-doc__sign {
  min-width: 150pt;
}
.axe-doc__sign-line {
  border-top: 0.75pt solid var(--doc-ink);
  padding-top: 4pt;
  margin-top: 28pt;
}
.axe-doc__sign-name {
  font-size: 10pt;
  font-weight: 700;
  color: var(--doc-ink);
}
.axe-doc__sign-title {
  font-size: 8.5pt;
  color: var(--doc-muted);
}

/* ------------------------------------------------------------
 *  Footer — top hairline + confidential · page indicator
 * ------------------------------------------------------------ */
.axe-doc__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: 22pt;
  padding-top: 6pt;
  border-top: 0.75pt solid var(--doc-rule);
  font-size: 7.5pt;
  color: var(--doc-muted);
}
.axe-doc__footer-page::after {
  /* 화면에서는 정적, 인쇄 시 @page counter 가 별도 처리 */
  content: attr(data-page);
}

/* ------------------------------------------------------------
 *  Layout helpers — 가로 문서 2-단, 페이지 나눔
 * ------------------------------------------------------------ */
.axe-doc__cols {
  column-count: 2;
  column-gap: 20pt;
  column-rule: 0.5pt solid var(--doc-rule);
}
.axe-doc__cols-3 {
  column-count: 3;
  column-gap: 16pt;
}
.axe-doc__pagebreak {
  break-after: page;
}
.axe-doc__pagebreak-before {
  break-before: page;
}
.axe-doc__nobreak {
  break-inside: avoid;
}
.axe-doc__spacer {
  height: 12pt;
}

/* ------------------------------------------------------------
 *  Print — backdrop/그림자 제거, @page margin 인계, 색 강제
 * ------------------------------------------------------------ */
@media print {
  html,
  body {
    background: #ffffff !important;
  }
  /* showcase chrome 숨김 */
  .axe-doc-toolbar,
  [data-print-hide] {
    display: none !important;
  }
  .axe-doc-stage {
    display: block;
    padding: 0;
    background: none;
    min-height: 0;
    gap: 0;
  }
  .axe-doc {
    /* 종이 시뮬레이션 해제 — @page 가 size/margin 인계 */
    width: auto;
    min-height: 0;
    margin: 0;
    padding: 0;
    box-shadow: none;
    border-radius: 0;
  }
  /* 밴드/배경/보더 색을 인쇄에 강제 (회색조 변환 방지) */
  .axe-doc,
  .axe-doc * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  /* 한 문서 = 한 orientation. 인쇄될 종이만 표시. */
  .axe-doc + .axe-doc {
    break-before: page;
  }
}

/* ============================================================
 * Phase 18 — Document data visuals (Track B)
 *
 * Resolved-spec 경계: 렌더러(React doc-viz 컴포넌트 · jinja _viz 매크로)는
 * 산술만 한다 — 선형 보간, 누적합, grid 곱셈. 축 tick 배열 · yMax · 표시
 * 문자열("₩60억", "15.8%")은 전부 호출자 책임 (ic-memo 의 기존 "str 표시값"
 * 규약의 연장). 함수 prop 금지.
 *
 * SVG geometry 계약: viewBox `0 0 482 H`(portrait 본문폭 170mm≈482pt,
 * 1 user unit ≡ 1pt) · 반폭 2-up 은 `0 0 231 H` · plot 마진
 * {l:36, r:8, t:8(valueLabels 시 16), b:18} · 좌표 소수 2자리 고정
 * (toFixed(2) / '%.2f'|format) · 색은 attribute 금지 — CSS 클래스/currentColor.
 * 기하 변경 = TS(doc-viz) · jinja(_viz) · golden(__fixtures__) 3점 동시 commit
 * (검증: scripts/doc-viz-parity/{gen-golden.mts,check_jinja.py}).
 *
 * 화면 대시보드 차트는 chart/Chart.tsx(recharts) — 본 섹션은 인쇄 문서 전용.
 * `.axe-doc` 내부 반응형 무대상 (by design — mm 고정 종이).
 * ============================================================ */

/* ------------------------------------------------------------
 *  신규 토큰 — 기존 .axe-doc 블록(상단) 무수정 원칙에 따라 append
 *  블록으로 추가 (cascade 가 동일 selector 의 변수 선언을 병합).
 *  카테고리 6색 = 휘도 분산 (실측 L* 29~63, 인접 시리즈 최소 ΔL*≈7,
 *  donut wrap 6↔1≈4.6) — 색 단독으로 흑백 복사 생존 불가. 그래서
 *  2-series bar 는 valueLabels 병기, donut 은 범례 표시값 병기가 규약
 *  (데모가 그 패턴). viz-1 은 --doc-accent(브랜드) 추종이라 rebrand 시
 *  사다리가 조용히 움직임 — 완전한 ≥12 사다리 재설계는
 *  B-ui-doc-viz-grayscale-ladder. (어드버서리얼 리뷰 2026-06-10)
 * ------------------------------------------------------------ */
.axe-doc {
  --doc-positive: #2b7a3f; /* callout --go 와 동일 (의미색 재사용) */
  --doc-negative: #c4321f; /* callout --pass 와 동일 */
  --doc-viz-1: var(--doc-accent); /* 1순위 = 브랜드 claret 추종 */
  --doc-viz-2: #31597f; /* 진청 */
  --doc-viz-3: #8a7f63; /* 모래 */
  --doc-viz-4: #c2913a; /* 황토 */
  --doc-viz-5: #4a7a55; /* 회록 */
  --doc-viz-6: #594a6b; /* 회보라 */
}

/* ------------------------------------------------------------
 *  표 variants
 * ------------------------------------------------------------ */
/* 재무표 — 첫 열 외 우정렬. :not() 형이라 jinja 루프에서 셀 클래스 불요. */
.axe-doc__table--financial th:not(:first-child),
.axe-doc__table--financial td:not(:first-child) {
  text-align: right;
  font-variant-numeric: tabular-nums lining-nums;
}
.axe-doc__table--compact {
  font-size: 8pt;
}
.axe-doc__table--compact th,
.axe-doc__table--compact td {
  padding: 3pt 6pt;
}
/* 인쇄 페이지마다 thead 반복 — 기본 동작이지만 명시 (긴 표 분할 대비) */
.axe-doc__table thead {
  display: table-header-group;
}
/* 짧은 표 opt-in — 표 전체를 한 페이지에 응집 */
.axe-doc__table--keep {
  break-inside: avoid;
}

/* 행 역할 — 회계 괘선 관례: 합계 = 위 단선 + 아래 이중선 */
.axe-doc__row--group th,
.axe-doc__row--group td {
  font-size: 7.5pt;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--doc-muted);
  background: var(--doc-band);
  border-bottom-color: var(--doc-rule-strong);
}
.axe-doc__row--group {
  break-after: avoid; /* 그룹 헤더가 페이지 끝에 고아로 남지 않게 */
}
.axe-doc__row--subtotal td,
.axe-doc__row--subtotal th {
  font-weight: 600;
  color: var(--doc-ink);
  border-top: 0.75pt solid var(--doc-rule-strong);
}
.axe-doc__row--total td,
.axe-doc__row--total th {
  font-weight: 700;
  color: var(--doc-ink);
  border-top: 1pt solid var(--doc-ink);
  border-bottom: 2.25pt double var(--doc-ink);
}
.axe-doc__row--subtotal,
.axe-doc__row--total {
  break-before: avoid; /* Chromium best-effort — 실패해도 데이터 무손실 */
}
.axe-doc__row--indent td:first-child,
.axe-doc__row--indent th:first-child {
  padding-left: 18pt;
}
.axe-doc__row--indent-2 td:first-child,
.axe-doc__row--indent-2 th:first-child {
  padding-left: 30pt;
}
/* 그룹+소계 응집 (opt-in) — cap table 의 다중 tbody 단위 페이지 나눔 */
tbody.axe-doc__rowgroup {
  break-inside: avoid;
}

/* 셀 유틸 */
.axe-doc__ctr {
  text-align: center;
}
/* 음수 — 괄호 (1,234) 는 표시 문자열 책임. 색+괄호 = 흑백 복사 이중 부호. */
.axe-doc__neg {
  color: var(--doc-negative);
}
.axe-doc__pos {
  color: var(--doc-positive);
}
.axe-doc__fn {
  font-size: 0.7em;
  vertical-align: super;
  color: var(--doc-accent-ink);
}
/* 지분 미니바 — inline 은 `--w` 데이터만 주입, 기존 print-color-adjust
 * (.axe-doc * exact) 가 gradient 인쇄를 보장. */
.axe-doc__cellbar {
  display: inline-block;
  vertical-align: -1pt;
  width: 36pt;
  height: 5pt;
  margin-right: 4pt;
  background: linear-gradient(
    to right,
    var(--doc-accent) var(--w, 0%),
    var(--doc-band) var(--w, 0%)
  );
  border: 0.5pt solid var(--doc-rule);
  border-radius: 1pt;
}

/* 비교표 — 열 사이 수직 헤어라인 + 제안 열 하이라이트 */
.axe-doc__table--compare th:not(:first-child) {
  text-align: center;
}
.axe-doc__table--compare td:not(:first-child),
.axe-doc__table--compare th:not(:first-child) {
  border-left: 0.5pt solid var(--doc-rule);
}
.axe-doc__table--compare th:first-child,
.axe-doc__table--compare td:first-child {
  color: var(--doc-muted);
  width: 24%;
}
/* colgroup 하이라이트 — col 은 배경만 가능 (보더 불가, CSS 2.1 제약) */
col.axe-doc__col--hl {
  background: var(--doc-accent-soft);
}
.axe-doc__table--compare thead th.axe-doc__th--hl {
  border-bottom: 1.5pt solid var(--doc-accent);
  color: var(--doc-accent-ink);
}

/* 표 단위 — caption 우측 float. 각주는 표 *밖* 형제 ul (__tnotes).
 * tfoot 금지: Chromium 인쇄에서 매 페이지 반복 — 합계/각주가 중복 출력됨. */
.axe-doc__table caption .axe-doc__table-unit {
  float: right;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}
.axe-doc__tnotes {
  margin: -6pt 0 10pt;
  padding: 0;
  list-style: none;
  font-size: 7.5pt;
  color: var(--doc-muted);
}
.axe-doc__tnotes li {
  margin-bottom: 1pt;
}

/* sr 유틸 — document.css 로컬 정의. jinja axe_css 채널 = tokens+document.css
 * 인라인 계약이라 indicators.css 의 .axe-sr-only 를 못 쓴다 (부재 검증됨). */
.axe-doc__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------------
 *  .axe-doc-viz — 서버 SVG 차트 (bar / line / donut)
 *  색 = series/key 클래스의 currentColor 단일 채널.
 * ------------------------------------------------------------ */
.axe-doc-viz {
  margin: 10pt 0;
  break-inside: avoid; /* figure = 원자 단위 (차트 H 200u ≈ 70mm — 항상 1페이지 내) */
}
.axe-doc-viz--wide {
  column-span: all; /* landscape 2-col 탈출 */
}
.axe-doc__figrow {
  display: flex;
  gap: 12pt; /* 2-up — 각 child flex:1, 반폭 viewBox 231 사용 */
}
.axe-doc__figrow > * {
  flex: 1;
  min-width: 0;
}
.axe-doc-viz__caption {
  font-size: 8pt;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--doc-muted);
  margin-bottom: 4pt;
}
.axe-doc-viz__svg {
  display: block;
  width: 100%;
  height: auto;
}
.axe-doc-viz__grid line {
  stroke: var(--doc-rule);
  stroke-width: 0.5px;
  shape-rendering: crispEdges;
}
.axe-doc-viz__axis line {
  stroke: var(--doc-rule-strong);
  stroke-width: 0.75px;
  shape-rendering: crispEdges;
}
.axe-doc-viz__tick,
.axe-doc-viz__xlabel {
  fill: var(--doc-muted);
  font-size: 7px;
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
}
.axe-doc-viz__value {
  fill: var(--doc-ink-2);
  font-size: 7px;
  font-variant-numeric: tabular-nums;
}
/* 카테고리 색 — series(SVG)·key(범례) 공용 currentColor 채널 */
.axe-doc-viz__series--1, .axe-doc-viz__key--1 { color: var(--doc-viz-1); }
.axe-doc-viz__series--2, .axe-doc-viz__key--2 { color: var(--doc-viz-2); }
.axe-doc-viz__series--3, .axe-doc-viz__key--3 { color: var(--doc-viz-3); }
.axe-doc-viz__series--4, .axe-doc-viz__key--4 { color: var(--doc-viz-4); }
.axe-doc-viz__series--5, .axe-doc-viz__key--5 { color: var(--doc-viz-5); }
.axe-doc-viz__series--6, .axe-doc-viz__key--6 { color: var(--doc-viz-6); }
.axe-doc-viz--bar .axe-doc-viz__series rect {
  fill: currentColor;
  shape-rendering: crispEdges;
}
.axe-doc-viz--line .axe-doc-viz__series polyline {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6px;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* 예측/2nd 시리즈 — dashed = 흑백 복사 redundant encoding */
.axe-doc-viz--line .axe-doc-viz__series--dashed polyline {
  stroke-dasharray: 4 2.5;
}
.axe-doc-viz--line .axe-doc-viz__series circle {
  fill: var(--doc-paper);
  stroke: currentColor;
  stroke-width: 1.2px;
}
/* donut — pathLength=100 기법: 슬라이스 = stroke-dasharray 백분율 산술만
 * (π·trig·rotate 전부 불요 — jinja 패리티 면적 최소화). */
.axe-doc-viz--donut .axe-doc-viz__slice {
  fill: none;
  stroke: currentColor;
  stroke-width: 26px;
}
.axe-doc-viz__donut-value {
  fill: var(--doc-ink);
  font-size: 15px;
  font-weight: 700;
  text-anchor: middle;
  font-variant-numeric: tabular-nums;
}
.axe-doc-viz__donut-label {
  fill: var(--doc-muted);
  font-size: 7px;
  text-anchor: middle;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
/* 범례 = SVG 밖 HTML ul — 스크린리더 · 한글 줄바꿈 · 타이포 일관 */
.axe-doc-viz__legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 4pt 12pt;
  margin: 4pt 0 0;
  padding: 0;
  font-size: 7.5pt;
  color: var(--doc-ink-2);
}
.axe-doc-viz__key::before {
  content: "";
  display: inline-block;
  width: 7pt;
  height: 7pt;
  margin-right: 3pt;
  vertical-align: -0.5pt;
  background: currentColor;
  border-radius: 1pt;
}

/* ------------------------------------------------------------
 *  .axe-doc-diagram — 투자 구조 다이어그램 (grid 배치, 수동 레이아웃)
 *  노드 kind = 색 아닌 테두리 *형태* 구분 (흑백 복사 의미 보존).
 *  신주/구주 = accent/파선 이중 부호.
 * ------------------------------------------------------------ */
.axe-doc-diagram__node rect {
  fill: var(--doc-paper);
  stroke: var(--doc-rule-strong);
  stroke-width: 0.9px;
}
.axe-doc-diagram__node--fund rect {
  fill: var(--doc-band);
  stroke: var(--doc-accent);
  stroke-width: 1.2px;
}
.axe-doc-diagram__node--spc rect {
  stroke-dasharray: 3 2;
}
.axe-doc-diagram__node--person rect {
  rx: 22px;
}
.axe-doc-diagram__node--target rect {
  stroke: var(--doc-ink);
  stroke-width: 1.4px;
}
.axe-doc-diagram__node-label {
  fill: var(--doc-ink);
  font-size: 8.5px;
  font-weight: 700;
  text-anchor: middle;
}
.axe-doc-diagram__node-sub {
  fill: var(--doc-muted);
  font-size: 7px;
  text-anchor: middle;
}
.axe-doc-diagram__edge path {
  fill: none;
  stroke: currentColor;
  stroke-width: 1px;
}
.axe-doc-diagram__edge {
  color: var(--doc-ink-2); /* equity 기본 */
}
.axe-doc-diagram__edge--new {
  color: var(--doc-accent); /* 신주 = accent 실선 */
}
.axe-doc-diagram__edge--old path {
  stroke-dasharray: 3.5 2.5; /* 구주 = 파선 */
}
.axe-doc-diagram__edge--flow {
  color: var(--doc-muted);
}
.axe-doc-diagram__edge--flow path {
  stroke-dasharray: 1.5 2.5; /* 출자/자금 = 점선 */
}
/* 화살촉 — marker 내용은 참조 엣지의 color 를 상속받지 못함 (context-fill
 * 미지원). marker 자체에 edge 클래스를 부여하고 본 규칙이 fill 을 채움.
 * specificity (0,2,1) — 위 `.axe-doc-diagram__edge path` 의 fill:none 을 이김. */
.axe-doc-diagram__edge path.axe-doc-diagram__edge-arrow {
  fill: currentColor;
  stroke: none;
}
/* 엣지 라벨 halo — 선 위 가독, 인쇄 안전 (paint-order 는 PDF 변환 시 보존) */
.axe-doc-diagram__edge-label,
.axe-doc-diagram__edge-sub {
  fill: currentColor;
  font-size: 7px;
  paint-order: stroke;
  stroke: var(--doc-paper);
  stroke-width: 2.5px;
}

/* ------------------------------------------------------------
 *  Print — sr 표는 인쇄물에서 제외 (HTML 소비자 전용 fallback)
 * ------------------------------------------------------------ */
@media print {
  .axe-doc__sr {
    display: none;
  }
}

/* ============================================================
   계약서 variant — .axe-doc--contract (2026-06)
   메모·서한의 chrome(masthead·meta 밴드·accent 색)을 걷어내고 법률문서 톤으로:
   가운데 제목 + 당사자 식별 + 번호 조항(장 가운데/조 굵게/항·호) + 서명·날인 + 페이지번호.
   .axe-doc 의 A4 종이·토큰·본문 prose·표 는 그대로 재활용 (양식 다 빼고 "문서").
   ============================================================ */
.axe-doc--contract { position: relative; padding-bottom: 24mm; }
.axe-doc--contract .axe-doc__masthead { display: none; }
.axe-doc--contract .axe-doc__title {
  text-align: center; letter-spacing: 0.36em; font-size: 16pt; font-weight: 700;
  color: var(--doc-ink); margin: 4mm 0 1.5mm; border: 0;
}
.axe-doc--contract .axe-doc__subtitle { text-align: center; color: var(--doc-muted); margin: 0 0 2mm; }
.axe-doc--contract .axe-doc__contract-rule { border: 0; border-top: 0.6pt solid var(--doc-rule-strong); margin: 4mm 0 5mm; }
.axe-doc--contract .axe-doc__parties { margin: 0 0 4mm; }
.axe-doc--contract .axe-doc__party { font-size: 10.5pt; line-height: 1.55; margin: 1.5mm 0; }
.axe-doc--contract .axe-doc__party-role { font-weight: 800; color: var(--doc-ink); }
/* 장 — 가운데, 액센트/괘선/카운터 제거 */
.axe-doc--contract .axe-doc__section-title,
.axe-doc--contract .axe-doc__section-title--accent {
  text-align: center; border: 0; background: none; color: var(--doc-ink);
  font-size: 12pt; font-weight: 800; letter-spacing: 0.04em; margin: 9mm 0 3.5mm; padding: 0;
}
.axe-doc--contract .axe-doc__section-title::before { content: none; }
/* 조 + 본문 */
.axe-doc--contract .axe-doc__body { font-size: 11pt; line-height: 1.7; color: var(--doc-ink); }
.axe-doc--contract .axe-doc__body h3 { font-size: 11pt; font-weight: 800; color: var(--doc-ink); margin: 5mm 0 1.5mm; }
.axe-doc--contract .axe-doc__body p { text-align: justify; margin: 1.5mm 0; }
.axe-doc--contract .axe-doc__body ol { padding-left: 8mm; }
.axe-doc--contract .axe-doc__body li { text-align: justify; margin: 1.2mm 0; }
/* 표 — 단순 검은색 1px 테두리(상하좌우 풀 그리드) + table-layout:fixed.
   컬럼 너비(%)는 표 내용을 LLM 이 판단해 <colgroup><col style="width:N%"> 로 주입한다
   (가변 콘텐츠를 가독성 좋게 정렬 — 주소·설명 넓게, 숫자·코드 좁게). */
.axe-doc--contract .axe-doc__table { table-layout: fixed; }
.axe-doc--contract .axe-doc__table th,
.axe-doc--contract .axe-doc__table td { border: 1px solid #1a1a1a; background: none; padding: 4pt 6pt;
  vertical-align: top; word-break: keep-all; overflow-wrap: break-word; }
.axe-doc--contract .axe-doc__table thead th { font-weight: 700; }
.axe-doc--contract .axe-doc__table caption { text-align: left; }
/* 서명·날인 — 통상 계약서식: 당사자별 세로 블록(회사명·주소·법인등록번호·대표이사명 (인)) */
.axe-doc--contract .axe-doc__signoff { display: block; border: 0; padding: 0; margin: 10mm 0 0; }
.axe-doc--contract .axe-doc__sign-intro { font-size: 10.5pt; margin: 0 0 4mm; }
.axe-doc--contract .axe-doc__sign { font-size: 10pt; line-height: 1.65; margin: 7mm 0; }
.axe-doc--contract .axe-doc__sign .role { font-weight: 800; }
.axe-doc--contract .axe-doc__sign .seal { float: right; color: var(--doc-muted); }
.axe-doc--contract .axe-doc__sign .addr { color: var(--doc-ink-2); }
/* 페이지번호 */
.axe-doc--contract .axe-doc__pagenum {
  position: absolute; left: 0; right: 0; bottom: 9mm; text-align: center;
  font-size: 9pt; color: var(--doc-muted); letter-spacing: 0.12em;
}
@media print { .axe-doc--contract .axe-doc__pagenum { display: none; } }

/* source: styles/code-theme.css */
/* ============================================================
 * AXE Labs — shiki code theme (css-variables)
 *
 * ServerCodeBlock 이 shiki `css-variables` 테마로 토큰을 렌더하고,
 * 본 파일이 --shiki-* 변수를 디자인 토큰에 매핑한다.
 * 값이 전부 var() 참조라 light/dark 블록의 *선언은 동일*하지만,
 * tokens/colors.css 의 스코핑 컨벤션(명시적 dark 블록 + OS 다크 미디어쿼리
 * fallback)을 그대로 미러링해 cascade 우선순위를 일치시킨다.
 *
 * ⚠ 본 파일은 어디서도 자동 import 되지 않는다 — 앱 세션이 globals 에 wiring.
 *
 * 팔레트 (해석값):
 *   light: keyword=clear blue · string=phthalo green · function=info ·
 *          comment=text-muted(italic) · constant=scarf orange ·
 *          punctuation=text-tertiary · fg=text-primary · bg=transparent
 *   dark : keyword=clear blue · string=phthalo green · function=info ·
 *          comment=text-muted · constant=warning · punctuation=text-tertiary
 * ============================================================ */

/* -------- LIGHT (default) -------- */
:root,
[data-theme="light"],
.light {
  --shiki-foreground: var(--text-primary);
  --shiki-background: transparent;
  --shiki-token-keyword: var(--accent);
  --shiki-token-string: var(--success);
  --shiki-token-string-expression: var(--success);
  --shiki-token-comment: var(--text-muted);
  --shiki-token-constant: var(--warning);
  --shiki-token-function: var(--info);
  --shiki-token-parameter: var(--text-secondary);
  --shiki-token-punctuation: var(--text-tertiary);
  --shiki-token-link: var(--info);
}

/* -------- DARK (explicit) -------- */
/* 선언은 light 와 동일 — 밑단 토큰이 모드에 따라 명도만 조정된다. */
[data-theme="dark"],
.dark {
  --shiki-foreground: var(--text-primary);
  --shiki-background: transparent;
  --shiki-token-keyword: var(--accent);
  --shiki-token-string: var(--success);
  --shiki-token-string-expression: var(--success);
  --shiki-token-comment: var(--text-muted);
  --shiki-token-constant: var(--warning);
  --shiki-token-function: var(--info);
  --shiki-token-parameter: var(--text-secondary);
  --shiki-token-punctuation: var(--text-tertiary);
  --shiki-token-link: var(--info);
}

/* -------- DARK (OS preference fallback) -------- */
/* colors.css 의 :root:not([data-theme="light"]):not(.light) 패턴 미러. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not(.light) {
    --shiki-foreground: var(--text-primary);
    --shiki-background: transparent;
    --shiki-token-keyword: var(--accent);
    --shiki-token-string: var(--success);
    --shiki-token-string-expression: var(--success);
    --shiki-token-comment: var(--text-muted);
    --shiki-token-constant: var(--warning);
    --shiki-token-function: var(--info);
    --shiki-token-parameter: var(--text-secondary);
    --shiki-token-punctuation: var(--text-tertiary);
    --shiki-token-link: var(--info);
  }
}

/* shiki 가 emit 하는 .line span 을 block 으로 — 줄 단위 배경/하이라이트 가능.
 * ServerCodeBlock 은 줄 사이 "\n" 텍스트 노드를 넣지 않으므로 이중 줄간격 없음. */
.axe-codeblock pre code .line {
  display: block;
}

/* comment italic — 토큰 색이 inline style(color:var(--shiki-token-comment))로
 * 나오므로 attribute substring 으로 타겟. (light 가이드의 italic 을 dark 에도
 * 동일 적용 — 관례상 양 모드 italic 이 일관적.) */
.axe-codeblock pre code span[style*="--shiki-token-comment"] {
  font-style: italic;
}

/* 빈 줄 보존 — ServerCodeBlock 은 줄 사이 \n 텍스트 노드를 생략하므로
 * 빈 .line 이 zero-height 로 붕괴하는 것을 방지. */
.axe-codeblock pre code .line:empty::after {
  content: "\00a0";
}

/* source: styles/tones.css */
/* ============================================================
 * AXE Labs — surface tones (taste-skill 학습 / D-ui-11)
 *
 * 톤 = 스코프드 레이어. `.axe-tone-*` 래퍼의 subtree 안에서만 디스플레이 페이스 ·
 * radius 스케일 · 숫자 표기를 재조합한다. **구조층은 불변** — gray ramp · bg/text ·
 * 보더 · 상태색(success/warning/danger/info) · 대비 AA · 그림자는 톤이 건드리지 않아
 * 다테넌트 대비/의미 보장이 유지된다. 브랜드 리컬러(theme-manifest --brand/accent/cta)와
 * **직교**하므로 어떤 브랜드 accent 위에서도 동일 톤이 작동한다.
 *
 *   .axe-tone-signature  브랜드 기본 — Pretendard · radius 기본.
 *                        axelabs.ai · blueprint · design.
 *   .axe-tone-editorial  문서 · 격식 — display=Clash(opt-in, 미로딩 시 Pretendard 폴백) ·
 *                        crisp radius. gate · layer · IC 메모.
 *   .axe-tone-console    데이터 · 터미널 — display=mono(Sarasa) · tight radius · tabular-nums.
 *                        index · matrix 대시보드.
 *
 * ── 중첩 안전(nesting) ── 각 톤은 tone-controlled 값 **전부를 재선언(complete reset)** 한다.
 *   그래서 톤 안에 다른 톤을 중첩해도 안쪽 톤이 바깥 값을 상속하지 않는다. descendant 요소
 *   셀렉터는 쓰지 않는다 — 상속 커스텀 프로퍼티 + inherit 되는 실제 속성(font-variant-numeric)
 *   만 써서, 바깥 톤의 규칙이 중첩 래퍼 *내부* 콘텐츠로 새는 것을 원천 차단(Codex lane-2 리뷰).
 *
 * 본문 텍스트는 톤 무관 --font-sans(Pretendard) 유지 — 가독성 우선(디스플레이 자리만 교체).
 * radius 값은 shape 전용(대비·상태 의미와 무관)이라 스코프 내 remap이 안전하다.
 * radius 기본(6/10/16)은 tokens/spacing.css 스케일의 재선언(reset baseline)이다.
 * ============================================================ */

.axe-tone-signature {
  --font-display: var(--font-sans);
  --radius-md: 6px;
  --radius-lg: 10px;
  --radius-xl: 16px;
  font-variant-numeric: normal;
}

.axe-tone-editorial {
  --font-display: var(--font-brand); /* Clash Display(opt-in) → 미로딩 시 --font-sans 폴백 */
  --radius-md: 4px; /* crisp — 문서/print 느낌 */
  --radius-lg: 8px;
  --radius-xl: 12px;
  font-variant-numeric: normal;
}

.axe-tone-console {
  --font-display: var(--font-mono); /* Sarasa Fixed K */
  --radius-md: 4px; /* tight — 기술/터미널 느낌 */
  --radius-lg: 5px;
  --radius-xl: 6px;
  font-variant-numeric: tabular-nums; /* 숫자 정렬(표·지표) */
}

/* source: styles/page-patterns.css */
/* ============================================================
 * AXE Landing / Authentication page patterns
 *
 * Stable renderer-neutral contract. React, maud, jinja, and static HTML
 * consumers use the same .axe-pattern-* classes from the Consumer Kit.
 * ============================================================ */

.axe-pattern-landing,
.axe-pattern-auth {
  --font-brand: var(--font-sans);
  --font-clash: var(--font-sans);
  font-family: var(--font-sans);
}

/* Shared pattern details ------------------------------------------------ */

.axe-pattern-skip-link {
  position: fixed;
  top: var(--space-2);
  left: var(--space-2);
  z-index: calc(var(--z-overlay) + 10);
  transform: translateY(calc(-100% - var(--space-5)));
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  background: var(--cta);
  color: var(--cta-fg);
  font-size: var(--text-sm);
  text-decoration: none;
  transition: transform var(--duration-fast) var(--ease-out);
}

.axe-pattern-skip-link:focus {
  transform: translateY(0);
}

/* Landing pattern ------------------------------------------------------- */

.axe-pattern-landing {
  min-width: 0;
  min-height: 100vh;
  background: var(--bg-base);
  color: var(--text-primary);
}

.axe-pattern-landing__nav {
  min-height: 64px;
  padding-inline:
    max(
      clamp(var(--space-4), 4vw, var(--space-8)),
      calc((100% - 76rem) / 2)
    );
}

/* 0.25.1 — 랜딩 바의 워드마크는 제품 이름이다. workspace rail brand
 * (.axe-workspace-entity) 와 같은 식자(sans · bold · −0.01em)와 같은 색(본문색)으로
 * 맞춘다: 색은 상태에 쓰고 이름에는 쓰지 않는다는 0.25 크롬 규칙을, 로그인 전 화면도
 * 따르게 하는 것이다. 종전 claret 틴트 + semibold 는 공개 랜딩과 로그인 후 workspace 의
 * 같은 "Design" 이 서로 다른 글자로 보이게 했다. */
.axe-pattern-landing__nav .axe-logo {
  font-family: var(--font-sans);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
}

.axe-pattern-landing__nav-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.axe-pattern-landing__nav > .axe-pattern-landing__nav-actions {
  margin-left: auto;
}

.axe-pattern-container {
  width: min(calc(100% - clamp(2.5rem, 7vw, 6rem)), 76rem);
  margin-inline: auto;
}

.axe-pattern-landing__hero {
  min-height: min(760px, calc(100vh - 64px));
  min-height: min(760px, calc(100dvh - 64px));
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(var(--space-7), 6vw, var(--space-10));
  padding-block: clamp(4.75rem, 10vw, 8rem);
}

.axe-pattern-landing__hero .axe-hero__content {
  max-width: 42rem;
}

.axe-pattern-landing__hero .axe-hero__title {
  max-width: 13ch;
  font-family: var(--font-sans);
  font-size: clamp(2.8rem, 5.1vw, 4.65rem);
  font-weight: var(--weight-medium);
  line-height: 1.04;
  letter-spacing: -0.045em;
  text-wrap: balance;
}

.axe-pattern-landing__hero .axe-hero__title em {
  color: var(--brand-claret);
  font-style: normal;
}

.axe-pattern-landing__hero .axe-hero__subtitle {
  max-width: 38rem;
  font-size: clamp(var(--text-base), 1.2vw, var(--text-xl));
  line-height: 1.72;
}

.axe-pattern-landing__hero .axe-hero__actions a {
  gap: var(--space-2);
}

.axe-pattern-landing__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-tertiary);
}

.axe-pattern-ops {
  width: min(100%, 34rem);
  min-width: 0;
  border: 1px solid var(--border-default);
  border-radius: 1.25rem;
  overflow: hidden;
  background: var(--bg-elevated);
  box-shadow: var(--shadow-xl);
}

.axe-pattern-ops__header {
  min-height: 68px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
}

.axe-pattern-ops__header > div {
  min-width: 0;
}

.axe-pattern-ops__overline,
.axe-pattern-ops__section-label {
  display: block;
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.3;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.axe-pattern-ops__header strong {
  display: block;
  margin-top: 3px;
  color: var(--text-primary);
  font-size: var(--text-sm);
}

.axe-pattern-ops__live-status {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--success);
  font-size: var(--text-xs);
}

.axe-pattern-ops__live-status > span {
  width: 7px;
  height: 7px;
  border-radius: var(--radius-full);
  background: var(--success);
  box-shadow: 0 0 0 4px var(--success-soft);
}

.axe-pattern-ops__prompt {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-subtle);
}

.axe-pattern-ops__agent-mark {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 1px solid color-mix(in srgb, var(--accent) 32%, var(--border-subtle));
  border-radius: var(--radius-md);
  background: var(--accent-soft);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}

.axe-pattern-ops__prompt p {
  margin: 0;
  color: var(--text-primary);
  font-size: var(--text-sm);
  line-height: 1.6;
}

.axe-pattern-ops__body {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  min-width: 0;
}

.axe-pattern-ops__plan,
.axe-pattern-ops__snapshot {
  min-width: 0;
  padding: var(--space-5);
}

.axe-pattern-ops__plan {
  border-right: 1px solid var(--border-subtle);
}

.axe-pattern-ops__plan ol {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
}

.axe-pattern-ops__plan li {
  position: relative;
  min-width: 0;
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  gap: var(--space-3);
  padding-bottom: var(--space-4);
}

.axe-pattern-ops__plan li:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 27px;
  bottom: 2px;
  left: 12px;
  width: 1px;
  background: var(--border-default);
}

.axe-pattern-ops__plan li > span {
  width: 26px;
  height: 26px;
  z-index: 1;
  display: grid;
  place-items: center;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-full);
  background: var(--bg-elevated);
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: 10px;
}

.axe-pattern-ops__plan li[data-state="done"] > span {
  border-color: color-mix(in srgb, var(--success) 36%, var(--border-default));
  background: var(--success-soft);
  color: var(--success);
}

.axe-pattern-ops__plan li[data-state="active"] > span {
  border-color: color-mix(in srgb, var(--accent) 38%, var(--border-default));
  background: var(--accent-soft);
  color: var(--accent);
}

.axe-pattern-ops__plan strong {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.axe-pattern-ops__plan strong {
  color: var(--text-primary);
  font-size: var(--text-xs);
}

.axe-pattern-ops__plan small {
  display: block;
  margin-top: 3px;
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  line-height: 1.4;
}

.axe-pattern-ops__attention {
  margin-top: var(--space-4);
  padding: var(--space-3);
  border: 1px solid color-mix(in srgb, var(--warning) 32%, var(--border-subtle));
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--warning-soft) 58%, var(--bg-elevated));
}

.axe-pattern-ops__attention > div {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
}

.axe-pattern-ops__attention span,
.axe-pattern-ops__attention strong {
  display: block;
  font-size: var(--text-xs);
}

.axe-pattern-ops__attention span {
  color: var(--text-secondary);
}

.axe-pattern-ops__attention strong {
  color: var(--text-primary);
}

.axe-pattern-ops__attention .axe-badge {
  margin-top: var(--space-3);
}

.axe-pattern-ops__attention p {
  margin: var(--space-2) 0 0;
  color: var(--text-secondary);
  font-size: var(--text-xs);
  line-height: 1.45;
}

.axe-pattern-ops__snapshot-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-3);
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--text-xs);
}

.axe-pattern-ops__snapshot-row span {
  color: var(--text-tertiary);
}

.axe-pattern-ops__snapshot-row strong {
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.axe-pattern-ops__footer {
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-inline: var(--space-5);
  border-top: 1px solid var(--border-subtle);
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.axe-pattern-landing__trust {
  min-height: 76px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  border-top: 1px solid var(--border-subtle);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
}

.axe-pattern-landing__trust > span {
  font-family: var(--font-mono);
}

.axe-pattern-landing__trust ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: clamp(var(--space-4), 4vw, var(--space-8));
}

.axe-pattern-landing__trust li {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.axe-pattern-landing__loop,
.axe-pattern-landing__systems,
.axe-pattern-landing__cta {
  scroll-margin-top: 72px;
  padding-block: clamp(5rem, 9vw, 8rem);
}

.axe-pattern-landing__loop {
  border-block: 1px solid var(--border-subtle);
  background: var(--bg-subtle);
}

.axe-pattern-landing__section-header {
  max-width: 48rem;
}

.axe-pattern-landing__section-header > span,
.axe-pattern-landing__cta-inner > div > span {
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.axe-pattern-landing__section-header h2,
.axe-pattern-landing__governance-inner h2,
.axe-pattern-landing__cta-inner h2 {
  margin: var(--space-3) 0 0;
  color: var(--text-primary);
  font-size: clamp(2rem, 4vw, 3.55rem);
  font-weight: var(--weight-medium);
  line-height: 1.08;
  letter-spacing: -0.04em;
  text-wrap: balance;
}

.axe-pattern-landing__section-header p,
.axe-pattern-landing__governance-inner p {
  max-width: 42rem;
  margin: var(--space-4) 0 0;
  color: var(--text-secondary);
  font-size: var(--text-base);
  line-height: 1.7;
}

.axe-pattern-landing__loop-grid {
  list-style: none;
  margin: clamp(var(--space-7), 6vw, var(--space-10)) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-top: 1px solid var(--border-default);
}

.axe-pattern-landing__loop-grid li {
  position: relative;
  min-width: 0;
  padding: var(--space-5) var(--space-5) 0 0;
}

.axe-pattern-landing__loop-grid li:not(:last-child) {
  border-right: 1px solid var(--border-subtle);
}

.axe-pattern-landing__loop-grid li:not(:first-child) {
  padding-left: var(--space-5);
}

.axe-pattern-landing__loop-grid li > span {
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.axe-pattern-landing__loop-grid strong {
  display: block;
  margin-top: var(--space-5);
  color: var(--text-primary);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
}

.axe-pattern-landing__loop-grid p {
  margin: var(--space-3) 0 0;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: 1.65;
}

.axe-pattern-landing__domain-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
  margin-top: clamp(var(--space-7), 6vw, var(--space-10));
}

.axe-pattern-landing__domain-card {
  min-width: 0;
  min-height: 20rem;
  display: flex;
  flex-direction: column;
  padding: clamp(var(--space-5), 3vw, var(--space-7));
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-xs);
}

.axe-pattern-landing__domain-topline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.axe-pattern-landing__domain-card h3 {
  margin: auto 0 0;
  padding-top: var(--space-8);
  color: var(--text-primary);
  font-size: clamp(var(--text-xl), 2vw, var(--text-2xl));
  font-weight: var(--weight-medium);
  line-height: 1.2;
  letter-spacing: -0.025em;
}

.axe-pattern-landing__domain-card p {
  margin: var(--space-3) 0 0;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: 1.65;
}

.axe-pattern-landing__domain-metric {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-6);
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.axe-pattern-landing__domain-metric > span {
  width: 7px;
  height: 7px;
  border-radius: var(--radius-full);
  background: var(--accent);
}

.axe-pattern-landing__domain-metric[data-state="success"] {
  color: var(--success);
}

.axe-pattern-landing__domain-metric[data-state="success"] > span {
  background: var(--success);
}

.axe-pattern-landing__governance {
  scroll-margin-top: 72px;
  padding: clamp(4.5rem, 8vw, 7rem) clamp(1.25rem, 5vw, 4rem);
}

.axe-pattern-landing__governance-inner {
  width: min(100%, 76rem);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(18rem, 0.9fr);
  align-items: end;
  gap: clamp(var(--space-8), 8vw, 8rem);
  padding: clamp(var(--space-6), 5vw, var(--space-10));
  border-radius: 1.5rem;
  background: var(--gray-12);
  color: var(--gray-1);
}

.axe-pattern-landing__governance-kicker {
  color: var(--gray-8);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.axe-pattern-landing__governance-inner h2 {
  color: var(--gray-1);
}

.axe-pattern-landing__governance-inner p {
  color: var(--gray-8);
}

.axe-pattern-landing__governance-list {
  margin: 0;
}

.axe-pattern-landing__governance-list > div {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr);
  gap: var(--space-4);
  padding-block: var(--space-4);
  border-bottom: 1px solid color-mix(in srgb, var(--gray-1) 18%, transparent);
}

.axe-pattern-landing__governance-list dt {
  color: var(--gray-8);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.axe-pattern-landing__governance-list dd {
  margin: 0;
  color: var(--gray-1);
  font-size: var(--text-sm);
}

.axe-pattern-landing__cta {
  padding-top: clamp(3rem, 6vw, 5rem);
}

.axe-pattern-landing__cta-inner {
  min-height: 14rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
  padding-block: var(--space-7);
  border-top: 1px solid var(--border-default);
}

.axe-pattern-landing__cta-inner h2 {
  max-width: 18ch;
  font-size: clamp(1.8rem, 3.4vw, 3rem);
}

.axe-pattern-landing__cta-inner .axe-btn a,
.axe-pattern-landing__cta-inner .axe-btn {
  gap: var(--space-2);
}

.axe-pattern-landing__footer {
  width: min(calc(100% - clamp(2.5rem, 7vw, 6rem)), 76rem);
  min-height: 84px;
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-5);
  border-top: 1px solid var(--border-subtle);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
}

.axe-pattern-landing__footer .axe-logo {
  font-family: var(--font-sans);
}

.axe-pattern-landing__footer > span {
  font-family: var(--font-mono);
}

.axe-pattern-landing__footer nav {
  justify-self: end;
  display: flex;
  gap: var(--space-5);
}

.axe-pattern-landing__footer nav a {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  color: var(--text-secondary);
  text-decoration: none;
}

.axe-pattern-landing__footer nav a:hover {
  color: var(--text-primary);
}

.axe-pattern-landing__footer nav a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Authentication pattern ----------------------------------------------- */

.axe-pattern-auth {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(20rem, 1fr) minmax(28rem, 1fr);
  background: var(--bg-base);
  color: var(--text-primary);
}

.axe-pattern-auth.axe-pattern-auth--centered {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
}

.axe-pattern-auth__topbar {
  min-height: 64px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-inline: max(var(--space-5), calc((100% - 76rem) / 2));
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-base);
}

.axe-pattern-auth__topbar .axe-logo {
  font-family: var(--font-sans);
  font-weight: var(--weight-semibold);
}

.axe-pattern-auth__topbar a:last-child {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  text-decoration: none;
}

.axe-pattern-auth__topbar a:last-child:hover {
  color: var(--text-primary);
}

.axe-pattern-auth__topbar a:last-child:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.axe-pattern-auth--centered .axe-pattern-auth__stage {
  min-height: 0;
  justify-content: flex-start;
  background: var(--bg-subtle);
}

.axe-pattern-auth--centered .axe-pattern-auth__card {
  width: min(100%, 28rem);
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

.axe-pattern-auth--centered .axe-pattern-auth__card-header {
  margin: 0 0 var(--space-6);
  text-align: center;
}

.axe-pattern-auth--centered .axe-pattern-auth__card-header h1 {
  font-size: 1.5rem;
  line-height: 1.3;
  letter-spacing: -0.025em;
}

.axe-pattern-auth--centered .axe-pattern-auth__card-header p {
  max-width: 34rem;
  margin-inline: auto;
}

.axe-pattern-auth--centered .axe-pattern-auth__support {
  width: min(100%, 28rem);
}

.axe-pattern-auth__context {
  min-width: 0;
  min-height: 43rem;
  display: flex;
  flex-direction: column;
  padding: clamp(2rem, 5vw, 5rem);
  border-right: 1px solid var(--border-subtle);
  background: var(--bg-subtle);
}

.axe-pattern-auth__context-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.axe-pattern-auth__context-top .axe-logo,
.axe-pattern-auth__card-brand .axe-logo {
  font-family: var(--font-sans);
  font-weight: var(--weight-semibold);
}

.axe-pattern-auth__context-top > span,
.axe-pattern-auth__card-brand > span {
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.axe-pattern-auth__context-copy {
  max-width: 36rem;
  margin-block: auto;
  padding-block: var(--space-9);
}

.axe-pattern-auth__context-kicker {
  color: var(--brand-claret);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.axe-pattern-auth__context-title {
  margin: var(--space-4) 0 0;
  color: var(--text-primary);
  font-size: clamp(2.35rem, 4.7vw, 4.25rem);
  font-weight: var(--weight-medium);
  line-height: 1.05;
  letter-spacing: -0.045em;
  text-wrap: balance;
}

.axe-pattern-auth__context-copy > p:last-child {
  max-width: 34rem;
  margin: var(--space-5) 0 0;
  color: var(--text-secondary);
  font-size: var(--text-base);
  line-height: 1.72;
}

.axe-pattern-auth__trust-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid var(--border-default);
}

.axe-pattern-auth__trust-list li {
  min-width: 0;
  padding: var(--space-4) var(--space-4) 0 0;
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  line-height: 1.55;
}

.axe-pattern-auth__trust-list li:not(:last-child) {
  border-right: 1px solid var(--border-subtle);
}

.axe-pattern-auth__trust-list li:not(:first-child) {
  padding-left: var(--space-4);
}

.axe-pattern-auth__trust-list svg,
.axe-pattern-auth__trust-index {
  display: block;
  margin-bottom: var(--space-3);
  color: var(--accent);
}

.axe-pattern-auth__trust-index {
  font-family: var(--font-mono);
}

.axe-pattern-auth__trust-list strong {
  display: block;
  margin-bottom: 3px;
  color: var(--text-primary);
  font-size: var(--text-xs);
}

.axe-pattern-auth__context-foot {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-7);
  color: var(--success);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.axe-pattern-auth__context-foot > span {
  width: 7px;
  height: 7px;
  border-radius: var(--radius-full);
  background: var(--success);
}

.axe-pattern-auth__stage {
  min-width: 0;
  min-height: 43rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: clamp(var(--space-6), 5vw, var(--space-10));
  background: var(--bg-base);
}

.axe-pattern-auth__card {
  width: min(100%, 27rem);
  padding: clamp(var(--space-6), 4vw, var(--space-8));
  border: 1px solid var(--border-default);
  border-radius: 1.25rem;
  background: var(--bg-elevated);
  box-shadow: var(--shadow-lg);
}

.axe-pattern-auth__card-brand {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.axe-pattern-auth__card-header {
  margin-block: var(--space-7) var(--space-6);
}

.axe-pattern-auth__card-header h1 {
  margin: 0;
  color: var(--text-primary);
  font-size: clamp(1.9rem, 4vw, 2.5rem);
  font-weight: var(--weight-medium);
  line-height: 1.1;
  letter-spacing: -0.035em;
}

.axe-pattern-auth__card-header p {
  margin: var(--space-3) 0 0;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: 1.65;
}

.axe-pattern-auth__provider,
.axe-pattern-auth__email-action {
  width: 100%;
}

.axe-pattern-auth__provider {
  justify-content: center;
}

.axe-pattern-auth__divider {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-3);
  margin-block: var(--space-5);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
}

.axe-pattern-auth__divider::before,
.axe-pattern-auth__divider::after {
  content: "";
  height: 1px;
  background: var(--border-subtle);
}

.axe-pattern-auth__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  border-radius: var(--radius-md);
}

.axe-pattern-auth__form:focus {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

.axe-pattern-auth__card .axe-status-banner {
  margin-top: var(--space-5);
}

.axe-pattern-auth__privacy {
  margin: var(--space-5) 0 0;
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  line-height: 1.6;
  text-align: center;
}

.axe-pattern-auth__privacy a,
.axe-pattern-auth__support a {
  color: var(--text-secondary);
  text-underline-offset: 3px;
}

.axe-pattern-auth__privacy a:hover,
.axe-pattern-auth__support a:hover {
  color: var(--text-primary);
}

.axe-pattern-auth__privacy a:focus-visible,
.axe-pattern-auth__support a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.axe-pattern-auth__support {
  width: min(100%, 27rem);
  display: flex;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
}

@media (min-width: 900px) {
  .axe-pattern-landing__hero {
    grid-template-columns: minmax(0, 1.03fr) minmax(25rem, 0.97fr);
  }
}

@media (max-width: 1023.98px) {
  .axe-pattern-auth {
    grid-template-columns: minmax(17rem, 0.8fr) minmax(27rem, 1.2fr);
  }

  .axe-pattern-auth__trust-list {
    grid-template-columns: minmax(0, 1fr);
  }

  .axe-pattern-auth__trust-list li {
    display: grid;
    grid-template-columns: 24px minmax(0, 1fr);
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-right: 0 !important;
    border-bottom: 1px solid var(--border-subtle);
  }

  .axe-pattern-auth__trust-list li:not(:first-child) {
    padding-left: 0;
  }

  .axe-pattern-auth__trust-list svg,
  .axe-pattern-auth__trust-index {
    margin: 0;
  }

  .axe-pattern-landing__domain-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .axe-pattern-landing__domain-card {
    min-height: 15rem;
  }
}

@media (max-width: 899.98px) {
  .axe-pattern-ops {
    width: 100%;
  }

  .axe-pattern-landing__loop-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .axe-pattern-landing__loop-grid li:nth-child(2) {
    border-right: 0;
  }

  .axe-pattern-landing__loop-grid li:nth-child(n + 3) {
    border-top: 1px solid var(--border-subtle);
  }

  .axe-pattern-landing__governance-inner {
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
  }

  .axe-pattern-landing__cta-inner {
    align-items: flex-start;
    flex-direction: column;
  }

  .axe-pattern-landing__footer {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .axe-pattern-landing__footer > span {
    display: none;
  }
}

@media (max-width: 799.98px) {
  .axe-pattern-auth {
    min-height: 100vh;
    min-height: 100dvh;
    display: block;
  }

  .axe-pattern-auth__context {
    min-height: auto;
    display: block;
    padding: var(--space-5) clamp(var(--space-5), 6vw, var(--space-7));
    border-right: 0;
    border-bottom: 1px solid var(--border-subtle);
  }

  .axe-pattern-auth__context-top > span {
    display: none;
  }

  .axe-pattern-auth__context-copy {
    margin: var(--space-7) 0 0;
    padding: 0;
  }

  .axe-pattern-auth__context-title {
    max-width: 18ch;
    font-size: clamp(1.75rem, 8vw, 2.5rem);
  }

  .axe-pattern-auth__context-copy > p:last-child {
    margin-top: var(--space-3);
    font-size: var(--text-sm);
  }

  .axe-pattern-auth__trust-list,
  .axe-pattern-auth__context-foot {
    display: none;
  }

  .axe-pattern-auth__stage {
    min-height: auto;
    padding: clamp(var(--space-7), 8vw, var(--space-10)) clamp(var(--space-5), 6vw, var(--space-7));
  }

  .axe-pattern-auth__card {
    border-radius: var(--radius-lg);
  }
}

@media (max-width: 767.98px) {
  .axe-pattern-landing__nav {
    min-height: 56px;
    padding-inline: var(--space-3);
  }

  .axe-pattern-landing__nav-actions {
    width: 100%;
    align-items: stretch;
    flex-direction: column;
  }

  .axe-pattern-landing__nav-actions .axe-btn {
    width: 100%;
    min-height: 44px;
  }

  .axe-pattern-landing__nav > .axe-pattern-landing__nav-actions {
    width: auto;
    grid-column: 3;
    justify-self: end;
    flex-direction: row;
  }

  .axe-pattern-landing__nav > .axe-pattern-landing__nav-actions .axe-btn {
    width: auto;
  }

  .axe-pattern-container,
  .axe-pattern-landing__footer {
    width: min(calc(100% - 2.5rem), 76rem);
  }

  .axe-pattern-landing__hero {
    min-height: auto;
    padding-block: clamp(3.75rem, 15vw, 6rem);
  }

  .axe-pattern-landing__hero .axe-hero__title {
    font-size: clamp(2.35rem, 11vw, 3.45rem);
  }

  .axe-pattern-landing__hero .axe-hero__subtitle {
    font-size: var(--text-base);
  }

  .axe-pattern-ops__body {
    grid-template-columns: minmax(0, 1fr);
  }

  .axe-pattern-ops__plan {
    border-right: 0;
    border-bottom: 1px solid var(--border-subtle);
  }

  .axe-pattern-landing__trust {
    min-height: 96px;
    align-items: flex-start;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-3);
  }

  .axe-pattern-landing__trust ul {
    width: 100%;
    justify-content: space-between;
    gap: var(--space-2);
  }

  .axe-pattern-landing__trust li {
    font-size: var(--text-xs);
  }

  .axe-pattern-landing__loop-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .axe-pattern-landing__loop-grid li,
  .axe-pattern-landing__loop-grid li:not(:first-child) {
    padding: var(--space-5) 0;
    border-top: 1px solid var(--border-subtle);
    border-right: 0;
  }

  .axe-pattern-landing__loop-grid li:first-child {
    border-top: 0;
  }

  .axe-pattern-landing__loop-grid strong {
    margin-top: var(--space-3);
  }

  .axe-pattern-landing__governance {
    padding-inline: var(--space-3);
  }

  .axe-pattern-landing__governance-inner {
    border-radius: var(--radius-xl);
  }

  .axe-pattern-landing__governance-list > div {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
  }

  .axe-pattern-landing__cta-inner .axe-btn {
    width: 100%;
  }

  .axe-pattern-landing__footer nav {
    gap: var(--space-3);
  }
}

@media (max-width: 479.98px) {
  .axe-pattern-landing__hero .axe-hero__actions {
    align-items: stretch;
    flex-direction: column;
  }

  .axe-pattern-landing__hero .axe-hero__actions .axe-btn {
    width: 100%;
  }

  .axe-pattern-ops__header,
  .axe-pattern-ops__footer {
    align-items: flex-start;
    flex-direction: column;
    justify-content: center;
  }

  .axe-pattern-ops__footer {
    padding-block: var(--space-3);
  }

  .axe-pattern-landing__trust ul {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .axe-pattern-landing__footer {
    min-height: 112px;
    align-items: start;
    grid-template-columns: minmax(0, 1fr);
    padding-block: var(--space-5);
  }

  .axe-pattern-landing__footer nav {
    justify-self: start;
  }

  .axe-pattern-auth__stage {
    padding-inline: var(--space-4);
  }

  .axe-pattern-auth__topbar {
    min-height: 56px;
    padding-inline: var(--space-4);
  }

  .axe-pattern-auth__context {
    padding: var(--space-4);
  }

  .axe-pattern-auth__context-copy {
    margin-top: var(--space-4);
  }

  .axe-pattern-auth__context-title {
    margin-top: var(--space-2);
    font-size: 1.5rem;
  }

  .axe-pattern-auth__context-copy > p:last-child {
    display: none;
  }

  .axe-pattern-auth__card {
    padding: var(--space-5);
    border-inline: 0;
    border-radius: 0;
    box-shadow: none;
  }

  .axe-pattern-auth__support {
    align-items: center;
    flex-direction: column;
  }
}

@media (prefers-reduced-motion: reduce) {
  .axe-pattern-skip-link,
  .axe-pattern-landing *,
  .axe-pattern-auth * {
    scroll-behavior: auto !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

@media (forced-colors: active) {
  .axe-pattern-ops__live-status > span,
  .axe-pattern-landing__domain-metric > span,
  .axe-pattern-auth__context-foot > span {
    border: 1px solid currentColor;
  }

  .axe-pattern-ops,
  .axe-pattern-landing__domain-card,
  .axe-pattern-auth__card,
  .axe-pattern-landing__governance-inner {
    border: 1px solid CanvasText;
  }
}

/* source: styles/gate-app-patterns.css */
/*
 * Gate application pattern
 * --------------------------------------------------------------------------
 * Canonical visual contract for Gate's authenticated application, workflow,
 * document, signer, and legacy single-card surfaces.
 *
 * Gate owns policy, data, routes, and copy. design.axelabs.ai owns every
 * selector below and ships it through the full Consumer Kit bundle. The root
 * class keeps Gate's compact server-rendered vocabulary from leaking into
 * other @axe/ui consumers.
 */

.axe-pattern-gate-app {
  margin: 0;
  background: var(--bg-base);
  color: var(--text-primary);
  font-family: var(
    --font-sans,
    "Pretendard Variable",
    Pretendard,
    -apple-system,
    "Apple SD Gothic Neo",
    "Malgun Gothic",
    sans-serif
  );
  font-size: var(--text-base);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
}

/* 클래스 없는 `<a>` 의 바닥값 — Gate 의 서버렌더 표면에는 어휘를 안 받은 앵커가
 * 많고, 이 세 규칙이 그것들에 색·hover 밑줄·포커스 링을 준다.
 *
 * **명시 재료는 여기서 빠진다.** `:not()` 목록이 그 명단이다: `.axe-btn` 과
 * `.axe-link`(0.38.7 신설) 는 자기 시각을 스스로 싣는 재료라, 이 포괄 규칙이
 * 같이 잡으면 재료와 바닥값이 같은 앵커를 두고 겹친다. `:where()` 가 특정도를
 * 0 으로 눕혀 두어 지금은 재료가 **나중에 오기 때문에** 이기지만, 그 승리는
 * 번들 파일 순서에 달린 것이지 규칙이 말한 것이 아니다 — 명단에서 빼면 애초에
 * 겹치지 않는다. **새 앵커 재료를 킷에 들이면 이 명단에 같이 올릴 것.** */
.axe-pattern-gate-app :where(main, nav.top) :where(a:not(.axe-btn, .axe-link)) {
  color: var(--accent);
  text-decoration: none;
}

.axe-pattern-gate-app :where(main, nav.top) :where(a:not(.axe-btn, .axe-link):hover) {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.axe-pattern-gate-app :where(main, nav.top) :where(a:not(.axe-btn, .axe-link):focus-visible) {
  border-radius: 2px;
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Application chrome --------------------------------------------------- */

.axe-pattern-gate-app nav.top {
  position: sticky;
  z-index: var(--z-sticky);
  top: 0;
  display: flex;
  height: 56px;
  align-items: center;
  gap: var(--space-5);
  padding: 0 var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-elevated);
  color: var(--text-primary);
}

.axe-pattern-gate-app nav.top .brand {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-primary);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-heading);
}

.axe-pattern-gate-app nav.top .brand:hover {
  text-decoration: none;
}

.axe-pattern-gate-app nav.top .brand .mark {
  display: inline-flex;
  width: 26px;
  height: 26px;
  flex: none;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-fg);
  font-size: 13px;
  font-weight: var(--weight-bold);
}

.axe-pattern-gate-app .nav-menu {
  display: flex;
  min-width: 0;
  flex: 1;
  align-items: center;
  gap: var(--space-1);
}

.axe-pattern-gate-app .nav-menu-scroll {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: var(--space-1);
  overflow-x: auto;
}

.axe-pattern-gate-app .nav-menu a {
  padding: 6px var(--space-3);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  white-space: nowrap;
}

.axe-pattern-gate-app .nav-menu a:hover {
  background: var(--bg-subtle);
  color: var(--text-primary);
  text-decoration: none;
}

.axe-pattern-gate-app .nav-menu a.active {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app nav.top .right {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-sm);
}

.axe-pattern-gate-app .userchip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 4px 12px 4px 5px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-full);
  background: var(--bg-subtle);
  color: var(--text-secondary);
  font-size: var(--text-xs);
}

.axe-pattern-gate-app .userchip .avatar {
  display: inline-flex;
  width: 22px;
  height: 22px;
  flex: none;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--accent-fg);
  font-size: 11px;
  font-weight: var(--weight-bold);
  text-transform: uppercase;
}

.axe-pattern-gate-app nav.top form {
  margin: 0;
}

/* Page frame ----------------------------------------------------------- */

.axe-pattern-gate-app .container {
  max-width: 1040px;
  margin: 0 auto;
  padding: var(--space-6) var(--space-5) var(--space-8);
}

.axe-pattern-gate-app .container.narrow {
  max-width: 880px;
}

.axe-pattern-gate-app .pagehead {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.axe-pattern-gate-app .pagehead > .axe-btn {
  flex: none;
}

.axe-pattern-gate-app :where(h1) {
  margin: 0 0 var(--space-2);
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-heading);
  line-height: var(--leading-heading);
}

.axe-pattern-gate-app :where(h2) {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-6) 0 var(--space-3);
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
}

.axe-pattern-gate-app :where(h2)::after {
  width: auto;
  height: 1px;
  flex: 1;
  background: var(--border-subtle);
  content: "";
}

.axe-pattern-gate-app :where(h3) {
  margin: 0 0 var(--space-2);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app p.sub {
  margin: 0 0 var(--space-5);
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

.axe-pattern-gate-app .meta {
  color: var(--text-secondary);
  font-size: var(--text-xs);
}

.axe-pattern-gate-app code.mono {
  padding: 1px 5px;
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  font-family: var(--font-mono);
  font-size: 12px;
  word-break: break-all;
}

.axe-pattern-gate-app .footer {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-8);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
  color: var(--text-muted);
  font-size: var(--text-xs);
}

/* Cards, metrics, actions --------------------------------------------- */

.axe-pattern-gate-app .card {
  margin-bottom: var(--space-4);
  padding: var(--space-5);
  /* The shell content column is `display:flex`, so a card is a flex item and shrinks by
     default. Combined with the overflow below (setting one axis forces the other to `auto`),
     a tall card collapsed to ~50px and clipped its own content — the 결재 처리 card rendered
     its 승인/반려/보류 buttons past the end of the document, unreachable by scrolling.
     Cards must keep their content height; only horizontal overflow may scroll. */
  flex-shrink: 0;
  overflow-x: auto;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
}

.axe-pattern-gate-app .gate-spaced-card {
  margin-top: var(--space-4);
}

.axe-pattern-gate-app .gate-workflow-progress {
  padding: 14px 22px 10px;
}

.axe-pattern-gate-app .grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-3);
}

.axe-pattern-gate-app .stat {
  position: relative;
  display: flex;
  padding: var(--space-4) var(--space-5);
  overflow: hidden;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  flex-direction: column;
}

.axe-pattern-gate-app .stat::before {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 3px;
  background: var(--accent);
  content: "";
}

.axe-pattern-gate-app .stat dt,
.axe-pattern-gate-app .stat dd {
  margin: 0;
}

.axe-pattern-gate-app .stat .n {
  order: -1;
  font-size: var(--text-3xl);
  font-weight: var(--weight-bold);
  line-height: 1.15;
}

.axe-pattern-gate-app .stat .l {
  margin-top: 4px;
  color: var(--text-secondary);
  font-size: var(--text-xs);
}

.axe-pattern-gate-app .gate-dashboard-status {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  flex: none;
  margin: var(--space-3) 0 0;
  overflow: hidden;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
}

.axe-pattern-gate-app .gate-dashboard-status > div {
  display: flex;
  min-width: 0;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 10px var(--space-4);
}

.axe-pattern-gate-app .gate-dashboard-status > div + div {
  border-left: 1px solid var(--border-subtle);
}

.axe-pattern-gate-app .gate-dashboard-status dt,
.axe-pattern-gate-app .gate-dashboard-status dd {
  margin: 0;
}

.axe-pattern-gate-app .gate-dashboard-status dt {
  color: var(--text-secondary);
  font-size: var(--text-xs);
}

.axe-pattern-gate-app .gate-dashboard-status dd {
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  white-space: nowrap;
}

.axe-pattern-gate-app .actions,
.axe-pattern-gate-app .actbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.axe-pattern-gate-app .actions {
  margin-bottom: var(--space-3);
}

/* 문서를 끝까지 읽은 결재자가 맨 위로 스크롤백하지 않고 결재할 수 있도록 뷰포트 하단에
   붙는다. 자연 위치는 콘텐츠 맨 끝이라 바닥까지 스크롤하면 sticky 가 풀려 제자리에 앉고,
   셸 콘텐츠의 하단 padding 이 마지막 카드와의 여백을 준다. `flex-shrink: 0` 은 .card 와
   같은 이유 — 셸 콘텐츠 열이 flex 라 눌려 사라지면 결재 수단 자체가 사라진다. */
.axe-pattern-gate-app .gate-actbar-sticky {
  position: sticky;
  z-index: var(--z-sticky);
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  flex-shrink: 0;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-lg);
}

.axe-pattern-gate-app .gate-actbar-sticky__label {
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

.axe-pattern-gate-app .gate-actbar-sticky__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.axe-pattern-gate-app .gate-primary-actions {
  margin-top: var(--space-5);
}

.axe-pattern-gate-app .gate-onboarding {
  margin-top: var(--space-4);
}

.axe-pattern-gate-app .gate-onboarding .grid {
  margin-top: var(--space-3);
}

.axe-pattern-gate-app .gate-onboarding .stat p {
  margin: var(--space-2) 0 var(--space-3);
}

/* Page sub-navigation --------------------------------------------------
 * The rail owns global movement; this strip owns the sections *inside* one
 * work area. Splitting them keeps a single truthful "you are here" marker.
 * The strip scrolls horizontally instead of hiding or wrapping items, so a
 * narrow viewport never removes a destination from reach.
 */

.axe-pattern-gate-app .gate-subnav {
  display: flex;
  gap: var(--space-1);
  margin: 0 0 var(--space-4);
  overflow-x: auto;
  border-bottom: 1px solid var(--border-subtle);
  scrollbar-width: thin;
}

.axe-pattern-gate-app .gate-subnav a {
  min-height: 40px;
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  padding-inline: var(--space-3);
  border-bottom: 2px solid transparent;
  color: var(--text-secondary);
  font-size: var(--text-sm);
  text-decoration: none;
  white-space: nowrap;
  transition:
    color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}

.axe-pattern-gate-app .gate-subnav a:hover {
  color: var(--text-primary);
}

/* `aria-current` is the state itself, so the style cannot drift from the
   announced state the way a parallel class can. */
.axe-pattern-gate-app .gate-subnav a[aria-current="page"] {
  border-bottom-color: var(--accent);
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app .gate-subnav a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* Rail AI chat ---------------------------------------------------------
 * `.gate-ai-chat` 는 executor 와 **같은 요소**에 붙는다
 * (`class="axe-agent-executor gate-ai-chat"`) — 래퍼가 아니다. 아래 자식 규칙이
 * `>` 로 executor 의 직계 슬롯을 잡기 때문에 이 배치가 계약의 일부다.
 *
 * `.axe-agent-executor` 는 `height: 100%` + `__scroll { flex: 1 1 auto;
 * min-height: 0; overflow-y: auto }` 로 **부모가 확정 높이를 준다**는 전제로 설계된
 * 컴포넌트인데, 컨텍스트 rail 에는 그 확정 높이를 주는 고리가 없었다.
 * `.axe-workspace-context` 는 `min-height: 100%` 라 내용이 길면 그대로 자라고, 탭 패널
 * `__body` 의 높이도 auto 로 해소된다 — `__scroll` 이 스크롤을 시작하지 못한 채 내용만큼
 * 자라 입력창을 rail 밖으로 밀어낸다.
 *
 * 0.23.3 은 이걸 `.gate-ai-chat` 에 절대 크기(`min(52vh, 30rem)`)를 줘서 막았지만, rail 이
 * 짧아지면 그 크기가 남은 공간보다 커져 같은 증상이 돌아온다 — 실측(2026-08-04, gate
 * headless Chrome) 1366x768 · 1280x800 · 1024x768 세 뷰포트에서 입력창 bottom 이 rail
 * bottom 을 각각 53 · 36 · 53px 초과했다. 그래서 절대 크기를 버리고 **남은 높이를 채우는**
 * flex 사슬로 바꾼다: rail 을 확정 높이로 고정하고, 채팅이 그 잔여를 받고, 컴포저는
 * 불가침(`flex: 0 0 auto`)으로 둔다. 같은 실측에서 1440x1080 · 1440x900 · 1366x768 ·
 * 1280x800 · 1024x768 다섯 뷰포트 모두 30턴을 쌓아도 입력창이 rail 안에 남는다.
 *
 * **1024x640 은 CSS 로 해결 불가**(같은 실측의 유일한 미해결). rail 441px 인데 고정
 * 크롬(헤더 105 + 탭 45 + 푸터 48) + 요약 60 + 고지 86 + 컴포저 151 = 495px 라 채팅 영역이
 * 0 이어도 54px 모자란다. 남은 수단은 배분이 아니라 제품 결정(rail 채팅 접기 또는 헤더
 * 축소)이므로, 이 파일에서 더 짜낼 것이 없다는 사실로 남긴다.
 *
 * ## 0.33.1 — 사슬을 **슬롯 ③(`__dock`)으로 재앵커**
 *
 * 0.33.0 이 `ContextPanel@1` 3슬롯을 도입하면서 채팅이 탭 패널
 * (`__body[data-gate-panel="ai"]`)에서 도크로 옮겨 갔는데, **확정 높이를 주던 고리는 옛
 * 선택자에 남아 있었다.** 신설 `__dock` 은 `flex: 0 0 auto` 라 자식에게 높이를 확정해
 * 주지 못하고, 그러면 `__scroll` 이 스크롤을 시작하지 못한 채 내용만큼 자란다 — 위 0.23.3
 * 결함의 재발이되 규모가 다르다. 실측(2026-08-09, 헤드리스 Chrome 1440x900, 30턴):
 *
 *   | 상태                          | 컴포저 bottom − rail bottom | `__scroll` 스크롤 |
 *   |-------------------------------|-----------------------------|-------------------|
 *   | 0.32.0 탭 패널 (대조군)       | **−164px** (안쪽)           | 5634/248 → yes    |
 *   | 0.33.0 + 도크 (재앵커 전)     | **+5385px** (밖으로)        | 5634/5634 → no    |
 *
 * 그래서 사슬의 중간 고리를 `__dock` + 그 안의 이동 노드로 옮긴다. `[data-axe-dock-root]`
 * 는 계약이 이름을 정한 셀렉터(`x-dom.dock.rootAttribute`)라 킷이 스타일할 수 있다 —
 * 소비자가 그 노드에 자기 클래스를 만들면 그것이 디자인 SoT 위반이 된다.
 *
 * 스코프: 아래 `.axe-workspace-context*` 는 공용 클래스지만 전부 `.axe-pattern-gate-app`
 * 루트 안이다 — 그 루트를 쓰지 않는 소비자(design · cortex · blueprint)의 계산 스타일
 * 변화는 0. 그리고 오늘 도크를 서빙하는 소비자는 gate 하나뿐이다(`dock: served`).
 */

.axe-pattern-gate-app .axe-workspace-context {
  height: 100%;
  min-height: 0;
}

/* 슬롯 ③ 이 **남은 높이를 받는다.** 기본 규칙의 `flex: 0 0 auto` 는 "접힌 입력 한 줄" 을
   전제한 값이라, transcript 가 사는 도크에서는 높이를 확정해 주지 못한다. */
.axe-pattern-gate-app .axe-workspace-context__dock {
  min-height: 0;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
}

/* 도크는 폭 전환·소프트 내비게이션을 넘어 **노드째 이동**하므로 호스트와 내용 사이에 이
   노드가 하나 더 있다. 사슬이 여기서 끊기면 아래 `.gate-ai-chat` 의 `flex: 1 1 auto` 가
   무의미해진다. */
.axe-pattern-gate-app .axe-workspace-context__dock > [data-axe-dock-root] {
  min-height: 0;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
}

.axe-pattern-gate-app .gate-ai-chat {
  height: auto;
  min-height: 0;
  flex: 1 1 auto;
}

.axe-pattern-gate-app .gate-ai-chat > .axe-agent-executor__scroll {
  min-height: 0;
  flex: 1 1 auto;
}

/* 칩 줄은 남은 높이를 놓고 transcript 와 경쟁하지 않는다 — 한 줄(2.25rem)까지 눌리고 그
   아래로는 자기 안에서 스크롤한다. 이게 없으면 flex item 의 auto min-size 가 내용 높이라
   칩이 늘수록 컴포저가 다시 밀려난다. */
.axe-pattern-gate-app .gate-ai-chat > .axe-agent-executor__tools {
  min-height: 2.25rem;
  flex: 0 1 auto;
  overflow-y: auto;
}

.axe-pattern-gate-app .gate-ai-chat > .axe-agent-executor__input {
  flex: 0 0 auto;
}

/* Product compositions -------------------------------------------------
 * These classes own arrangement only. Controls, tables, timelines, empty
 * states, and banners keep their canonical .axe-* primitive styling.
 */

.axe-pattern-gate-app .gate-resource-toolbar {
  display: grid;
  grid-template-columns: minmax(15rem, 1fr) auto auto auto;
  align-items: end;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.axe-pattern-gate-app .gate-resource-toolbar > form[role="search"] {
  min-width: 0;
}

.axe-pattern-gate-app .gate-resource-toolbar > [role="group"] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.axe-pattern-gate-app .gate-resource-toolbar > output {
  align-self: center;
  color: var(--text-secondary);
  font-size: var(--text-xs);
  white-space: nowrap;
}

.axe-pattern-gate-app .gate-resource-toolbar > .actions {
  justify-content: flex-end;
  margin: 0;
}

.axe-pattern-gate-app .gate-detail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(15rem, 18rem);
  align-items: start;
  gap: var(--space-5);
}

.axe-pattern-gate-app .gate-detail-layout > :where(article, aside) {
  min-width: 0;
}

.axe-pattern-gate-app .gate-detail-layout > aside {
  position: sticky;
  top: calc(var(--app-shell-topbar-h, 56px) + var(--space-5));
}

.axe-pattern-gate-app .gate-detail-layout > aside .kv {
  grid-template-columns: 90px minmax(0, 1fr);
}

.axe-pattern-gate-app .gate-detail-layout > aside .kv dd {
  overflow-wrap: anywhere;
}

.axe-pattern-gate-app .gate-form-layout {
  display: grid;
  gap: var(--space-5);
}

.axe-pattern-gate-app .gate-form-layout > fieldset {
  min-width: 0;
  margin: 0;
  padding: var(--space-5);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
}

.axe-pattern-gate-app .gate-form-layout > fieldset > legend {
  padding: 0 var(--space-2);
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app .gate-form-layout > fieldset > div {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
}

.axe-pattern-gate-app .gate-copy-field {
  display: grid;
  gap: var(--space-2);
}

.axe-pattern-gate-app .gate-copy-field > div {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-2);
}

.axe-pattern-gate-app .gate-copy-field > p {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--text-xs);
}

.axe-pattern-gate-app .gate-secret-reveal {
  padding: var(--space-4);
  border: 1px solid var(--warning);
  border-radius: var(--radius-lg);
  background: var(--warning-soft);
}

.axe-pattern-gate-app .gate-secret-reveal > summary {
  color: var(--text-primary);
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app .gate-secret-reveal[open] > summary {
  margin-bottom: var(--space-3);
}

.axe-pattern-gate-app .gate-secret-reveal > p {
  margin: 0 0 var(--space-3);
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

.axe-pattern-gate-app .gate-task-shell {
  min-height: calc(100vh - var(--app-shell-topbar-h, 56px));
  min-height: calc(100dvh - var(--app-shell-topbar-h, 56px));
  background: var(--bg-base);
}

.axe-pattern-gate-app .gate-task-shell__body {
  width: min(100%, 68rem);
  margin: 0 auto;
  padding: var(--space-6) var(--space-5) calc(var(--space-8) + 76px);
}

.axe-pattern-gate-app .gate-task-shell__footer {
  position: sticky;
  z-index: var(--z-sticky);
  bottom: 0;
  border-top: 1px solid var(--border-subtle);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
}

.axe-pattern-gate-app .gate-task-shell__footer > div {
  display: flex;
  width: min(100%, 68rem);
  min-height: 64px;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  margin: 0 auto;
  padding: var(--space-2) var(--space-5);
}

/* Dense tables, filters, dropdowns ------------------------------------ */

.axe-pattern-gate-app :where(table:not([class*="axe-"])) {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.axe-pattern-gate-app :where(table:not([class*="axe-"])) :where(th, td) {
  padding: 9px 12px;
  border-bottom: 1px solid var(--border-subtle);
  text-align: left;
  vertical-align: middle;
}

.axe-pattern-gate-app :where(table:not([class*="axe-"])) :where(thead th) {
  color: var(--text-tertiary);
  font-size: 11px;
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

.axe-pattern-gate-app :where(table:not([class*="axe-"])) :where(tbody tr:last-child td) {
  border-bottom: 0;
}

.axe-pattern-gate-app :where(table:not([class*="axe-"])) :where(tbody tr.is-interactive:hover) {
  background: var(--bg-subtle);
}

.axe-pattern-gate-app .empty {
  padding: var(--space-5) var(--space-2);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  text-align: center;
}

.axe-pattern-gate-app .empty::before {
  display: block;
  margin-bottom: 4px;
  color: var(--text-muted);
  content: "○";
  font-size: 18px;
}

.axe-pattern-gate-app .tagbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0 0 var(--space-4);
}

.axe-pattern-gate-app .chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 11px;
  border-radius: var(--radius-full);
  background: var(--bg-subtle);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: 1.5;
  text-decoration: none;
}

.axe-pattern-gate-app .chip:hover {
  background: var(--info-soft);
  color: var(--info);
}

.axe-pattern-gate-app .chip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.axe-pattern-gate-app .chip.active {
  background: var(--accent);
  color: var(--accent-fg);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app .chip .cnt {
  color: var(--text-muted);
  font-size: var(--text-xs);
}

.axe-pattern-gate-app .chip.active .cnt {
  color: inherit;
}

.axe-pattern-gate-app .chip.sm {
  padding: 2px 9px;
  font-size: var(--text-xs);
}

.axe-pattern-gate-app .tagcell {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.axe-pattern-gate-app .barlabel {
  margin-right: 2px;
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app .navdrop {
  position: relative;
  display: inline-block;
  flex: none;
}

.axe-pattern-gate-app .navdrop > summary {
  padding: 6px 10px;
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--text-sm);
  list-style: none;
}

.axe-pattern-gate-app .navdrop > summary::-webkit-details-marker {
  display: none;
}

.axe-pattern-gate-app .navdrop > summary:hover {
  background: var(--bg-subtle);
  color: var(--text-primary);
}

.axe-pattern-gate-app .navdrop[open] > summary {
  color: var(--text-primary);
}

.axe-pattern-gate-app .navdrop-menu {
  position: absolute;
  z-index: var(--z-overlay);
  top: 100%;
  left: 0;
  display: flex;
  min-width: 160px;
  flex-direction: column;
  margin-top: 4px;
  padding: 4px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-md);
}

.axe-pattern-gate-app .navdrop-menu a {
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  text-decoration: none;
  white-space: nowrap;
}

.axe-pattern-gate-app .navdrop-menu a:hover {
  background: var(--info-soft);
  color: var(--info);
}

/* State badges and workflow ------------------------------------------- */

.axe-pattern-gate-app .badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 10px;
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  line-height: 1.6;
  white-space: nowrap;
}

.axe-pattern-gate-app .badge::before {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-full);
  background: currentColor;
  content: "";
  opacity: 0.7;
}

.axe-pattern-gate-app .badge.draft,
.axe-pattern-gate-app .badge.withdrawn,
.axe-pattern-gate-app .badge.pending {
  background: var(--bg-subtle);
  color: var(--text-secondary);
}

.axe-pattern-gate-app .badge.submitted,
.axe-pattern-gate-app .badge.in_review {
  background: var(--info-soft);
  color: var(--info);
}

.axe-pattern-gate-app .badge.approved,
.axe-pattern-gate-app .badge.done,
.axe-pattern-gate-app .badge.ok {
  background: var(--success-soft);
  color: var(--success);
}

.axe-pattern-gate-app .badge.rejected,
.axe-pattern-gate-app .badge.bad {
  background: var(--danger-soft);
  color: var(--danger);
}

.axe-pattern-gate-app .badge.held {
  background: var(--warning-soft);
  color: var(--warning);
}

.axe-pattern-gate-app .badge.executing {
  background: var(--accent-soft);
  color: var(--accent);
}

.axe-pattern-gate-app .steps {
  display: flex;
  align-items: flex-start;
  margin: var(--space-4) 0 var(--space-1);
}

.axe-pattern-gate-app .step {
  position: relative;
  min-width: 0;
  flex: 1;
  text-align: center;
}

.axe-pattern-gate-app .step .dot {
  position: relative;
  z-index: 2;
  display: flex;
  width: 26px;
  height: 26px;
  align-items: center;
  justify-content: center;
  margin: 0 auto;
  border: 2px solid var(--border-subtle);
  border-radius: var(--radius-full);
  background: var(--bg-elevated);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: var(--weight-bold);
}

.axe-pattern-gate-app .step .lbl {
  margin-top: 6px;
  color: var(--text-secondary);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

.axe-pattern-gate-app .step:not(:first-child)::before {
  position: absolute;
  z-index: 1;
  top: 13px;
  right: calc(50% + 13px);
  left: calc(-50% + 13px);
  height: 2px;
  background: var(--border-subtle);
  content: "";
}

.axe-pattern-gate-app .step.done .dot {
  border-color: var(--success);
  background: var(--success);
  color: var(--text-inverse);
}

.axe-pattern-gate-app .step.done .lbl {
  color: var(--success);
}

.axe-pattern-gate-app .step.done:not(:first-child)::before,
.axe-pattern-gate-app .step.current:not(:first-child)::before {
  background: var(--success);
}

.axe-pattern-gate-app .step.current .dot {
  border-color: var(--accent);
  background: var(--accent);
  box-shadow: 0 0 0 5px var(--accent-soft);
  color: var(--accent-fg);
}

.axe-pattern-gate-app .step.current .lbl {
  color: var(--accent);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app .step.halted .dot {
  border-color: var(--danger);
  background: var(--danger);
  color: var(--text-inverse);
}

.axe-pattern-gate-app .step.halted .lbl {
  color: var(--danger);
}

/* Alerts and forms ----------------------------------------------------- */

.axe-pattern-gate-app .notice,
.axe-pattern-gate-app .alert {
  padding: var(--space-3) var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-lg);
  font-size: var(--text-sm);
}

.axe-pattern-gate-app .notice {
  border-color: var(--danger);
  background: var(--danger-soft);
  color: var(--danger);
}

.axe-pattern-gate-app .notice > :first-child,
.axe-pattern-gate-app .alert > :first-child {
  margin-top: 0;
}

.axe-pattern-gate-app .notice > :last-child,
.axe-pattern-gate-app .alert > :last-child {
  margin-bottom: 0;
}

.axe-pattern-gate-app .alert {
  margin-bottom: var(--space-3);
}

.axe-pattern-gate-app .gate-feedback {
  margin-top: var(--space-3);
}

.axe-pattern-gate-app .alert.info {
  border-color: var(--info);
  background: var(--info-soft);
  color: var(--info);
}

.axe-pattern-gate-app .alert.success {
  border-color: var(--success);
  background: var(--success-soft);
  color: var(--success);
}

.axe-pattern-gate-app .alert.warn {
  border-color: var(--warning);
  background: var(--warning-soft);
  color: var(--warning);
}

.axe-pattern-gate-app form.inline {
  margin: 0;
}

.axe-pattern-gate-app :where(label:not([class*="axe-"])) {
  display: block;
  margin: var(--space-4) 0 6px;
  color: var(--text-primary);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app :where(label:not([class*="axe-"])[data-req])::after {
  color: var(--danger);
  content: " *";
  font-weight: var(--weight-bold);
}

.axe-pattern-gate-app :where(label.check-row[data-req])::after {
  content: none;
}

.axe-pattern-gate-app :where(label.check-row[data-req]) > span::after {
  color: var(--danger);
  content: " *";
  font-weight: var(--weight-bold);
}

.axe-pattern-gate-app :where(
  input[type="text"]:not([class*="axe-"]),
  input[type="search"]:not([class*="axe-"]),
  input[type="email"]:not([class*="axe-"]),
  input[type="password"]:not([class*="axe-"]),
  input[type="number"]:not([class*="axe-"]),
  input[type="url"]:not([class*="axe-"]),
  input[type="date"]:not([class*="axe-"]),
  select:not([class*="axe-"]),
  textarea:not([class*="axe-"])
) {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-family: inherit;
  font-size: var(--text-sm);
}

.axe-pattern-gate-app :where(
  input:not([class*="axe-"]),
  select:not([class*="axe-"]),
  textarea:not([class*="axe-"])
):focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
  outline: none;
}

.axe-pattern-gate-app :where(
  input[type="checkbox"]:not([class*="axe-"]),
  input[type="file"]:not([class*="axe-"])
):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.axe-pattern-gate-app :where(textarea:not([class*="axe-"])) {
  resize: vertical;
}

.axe-pattern-gate-app :where(textarea.code) {
  min-height: 380px;
  background: var(--bg-elevated);
  font-family: var(--font-mono);
  font-size: 12.5px;
  line-height: 1.6;
}

.axe-pattern-gate-app :where(input[type="file"]:not([class*="axe-"])) {
  width: 100%;
  padding: 10px;
  border: 1.5px dashed var(--border-default);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--text-xs);
}

.axe-pattern-gate-app :where(input[type="file"]:not([class*="axe-"])):hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.axe-pattern-gate-app :where(input[type="file"]:not([class*="axe-"])):focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
  outline: none;
}

.axe-pattern-gate-app :where(input[type="checkbox"]:not([class*="axe-"])) {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
}

.axe-pattern-gate-app .hint {
  margin-top: 5px;
  color: var(--text-secondary);
  font-size: var(--text-xs);
}

.axe-pattern-gate-app .comment-row textarea {
  min-height: 56px;
}

.axe-pattern-gate-app .check-row {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin-top: var(--space-3);
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
}

.axe-pattern-gate-app .check-row input {
  flex: none;
  margin-top: 2px;
}

.axe-pattern-gate-app .kv {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 7px 16px;
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
}

.axe-pattern-gate-app .kv dt {
  color: var(--text-secondary);
}

.axe-pattern-gate-app .kv dd {
  margin: 0;
  word-break: break-word;
}

/* Document, signature, history ---------------------------------------- */

.axe-pattern-gate-app .axe-doc-stage {
  border-radius: var(--radius-lg);
}

.axe-pattern-gate-app .axe-doc h1 {
  margin: 0 0 14pt;
  font-size: 16pt;
  letter-spacing: 0.06em;
  text-align: center;
}

.axe-pattern-gate-app .axe-doc h2 {
  display: block;
  margin: 12pt 0 5pt;
  color: var(--doc-ink);
  font-size: 11.5pt;
  font-weight: var(--weight-bold);
  letter-spacing: normal;
  line-height: normal;
  text-transform: none;
}

.axe-pattern-gate-app .axe-doc h2::after {
  content: none;
}

.axe-pattern-gate-app .axe-doc h3 {
  margin: 12pt 0 5pt;
  color: var(--doc-ink);
  font-size: 11pt;
  font-weight: var(--weight-bold);
  line-height: normal;
}

.axe-pattern-gate-app .axe-doc table {
  width: 100%;
  margin: 6pt 0;
  border: 1px solid var(--doc-rule);
  border-collapse: collapse;
  font-size: 9.5pt;
}

.axe-pattern-gate-app .axe-doc th {
  width: 32%;
  padding: 5pt 7pt;
  border-bottom: 1px solid var(--doc-rule);
  background: var(--doc-band);
  color: var(--doc-ink-2);
  font-size: 9.5pt;
  font-weight: var(--weight-semibold);
  letter-spacing: normal;
  text-align: left;
  text-transform: none;
}

.axe-pattern-gate-app .axe-doc td {
  padding: 5pt 7pt;
  border-bottom: 1px solid var(--doc-rule);
}

.axe-pattern-gate-app .axe-doc tbody tr:hover {
  background: transparent;
}

.axe-pattern-gate-app .axe-doc ol {
  padding-left: 16pt;
}

.axe-pattern-gate-app .axe-doc li {
  margin-bottom: 2.5pt;
}

.axe-pattern-gate-app .axe-doc p {
  margin: 5pt 0;
}

.axe-pattern-gate-app .docbody {
  margin: var(--space-2) 0 var(--space-1);
  padding: var(--space-6);
  overflow-x: auto;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
}

.axe-pattern-gate-app .docbody img {
  max-width: 100%;
}

.axe-pattern-gate-app .sig-section {
  margin-top: 18pt;
  padding-top: 10pt;
  border-top: 1.5px solid var(--doc-rule-strong);
}

.axe-pattern-gate-app .sig-section .sig-title {
  margin-bottom: 6pt;
  font-size: 11.5pt;
  font-weight: var(--weight-bold);
}

.axe-pattern-gate-app .sig-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12pt;
  padding: 8pt 2pt;
  border-bottom: 1px dashed var(--doc-rule);
}

.axe-pattern-gate-app .sig-row:last-child {
  border-bottom: 0;
}

.axe-pattern-gate-app .sig-who .sig-name {
  font-size: 11pt;
  font-weight: var(--weight-bold);
}

.axe-pattern-gate-app .sig-who .sig-sub {
  margin-top: 2pt;
  color: var(--doc-muted);
  font-size: 8.5pt;
}

.axe-pattern-gate-app .sig-mark {
  position: relative;
  min-width: 150px;
  color: var(--doc-muted);
  font-size: 10pt;
  text-align: right;
}

.axe-pattern-gate-app .sig-mark .in {
  letter-spacing: 0.2em;
}

.axe-pattern-gate-app .sig-mark img.stamp {
  position: absolute;
  top: 50%;
  right: 6px;
  height: 62px;
  opacity: 0.93;
  mix-blend-mode: multiply;
  pointer-events: none;
  transform: translateY(-54%) rotate(-3deg);
}

.axe-pattern-gate-app .sig-mark .signed-label {
  display: inline-block;
  padding: 1px 8px;
  border: 1.5px solid var(--doc-accent);
  border-radius: 4px;
  color: var(--doc-accent);
  font-size: 8.5pt;
  font-weight: var(--weight-bold);
  transform: rotate(-2deg);
}

.axe-pattern-gate-app .events {
  margin: 0;
  padding: 0;
  list-style: none;
}

.axe-pattern-gate-app .events li {
  position: relative;
  padding: 0 0 14px 22px;
  font-size: var(--text-xs);
}

.axe-pattern-gate-app .events li::before {
  position: absolute;
  top: 6px;
  left: 5px;
  width: 7px;
  height: 7px;
  border-radius: var(--radius-full);
  background: var(--accent);
  content: "";
}

.axe-pattern-gate-app .events li::after {
  position: absolute;
  top: 15px;
  bottom: -2px;
  left: 8px;
  width: 1.5px;
  background: var(--border-subtle);
  content: "";
}

.axe-pattern-gate-app .events li:last-child::after {
  display: none;
}

.axe-pattern-gate-app .events .t {
  color: var(--text-secondary);
}

.axe-pattern-gate-app .gate-document-hash {
  margin-top: var(--space-3);
}

.axe-pattern-gate-app .gate-section-note {
  margin: 0 0 var(--space-4);
}

.axe-pattern-gate-app .gate-file-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
  flex-wrap: wrap;
}

.axe-pattern-gate-app .gate-file-name {
  font-weight: var(--weight-medium);
}

.axe-pattern-gate-app .gate-file-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.axe-pattern-gate-app .gate-pdf-frame {
  width: 100%;
  height: min(780px, 72vh);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--doc-paper);
}

.axe-pattern-gate-app .gate-extract {
  margin-top: var(--space-4);
}

.axe-pattern-gate-app .gate-extract > summary {
  padding: 6px 0;
  cursor: pointer;
  font-weight: var(--weight-medium);
}

.axe-pattern-gate-app .gate-extract-doc {
  margin-top: var(--space-2);
  padding: var(--space-5) var(--space-6);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--doc-paper);
  color: var(--doc-ink);
}

.axe-pattern-gate-app .gate-action-note {
  margin-left: var(--space-2);
}

/* Transitional single-card and signer surfaces ----------------------- */

.axe-pattern-gate-app .landing {
  max-width: 560px;
  margin: 9vh auto 0;
  padding: 0 20px;
  text-align: center;
}

.axe-pattern-gate-app .landing .logo {
  color: var(--accent);
  font-size: var(--text-4xl);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-heading);
}

.axe-pattern-gate-app .landing h1 {
  margin-top: var(--space-4);
}

.axe-pattern-gate-app .landing .card {
  width: 100%;
  max-width: 520px;
  margin: var(--space-3) auto 0;
  text-align: left;
}

.axe-pattern-gate-app .landing.gate-legal {
  max-width: 760px;
}

.axe-pattern-gate-app .landing .gate-card--narrow {
  max-width: 420px;
}

.axe-pattern-gate-app .landing .gate-card--wide {
  max-width: 720px;
  line-height: var(--leading-relaxed);
}

.axe-pattern-gate-app .landing .notice {
  text-align: left;
}

.axe-pattern-gate-app .landing .actions {
  justify-content: center;
}

.axe-pattern-gate-app .gate-status-message,
.axe-pattern-gate-app .gate-status-meta {
  margin: 0;
}

.axe-pattern-gate-app .gate-status-message + .gate-status-meta {
  margin-top: 6px;
}

.axe-pattern-gate-app .gate-portal-login,
.axe-pattern-gate-app .gate-inline-action {
  margin-top: var(--space-3);
}

.axe-pattern-gate-app .gate-portal-login + .hint {
  margin-top: var(--space-2);
}

.axe-pattern-gate-app .gate-nav-context {
  color: var(--text-tertiary);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}

.axe-pattern-gate-app .seal-hero {
  margin-bottom: var(--space-4);
  padding: var(--space-6) var(--space-4) var(--space-5);
  border: 1px solid;
  border-radius: var(--radius-lg);
  text-align: center;
}

.axe-pattern-gate-app .seal-hero.ok {
  border-color: var(--success);
  background: var(--success-soft);
  color: var(--success);
}

.axe-pattern-gate-app .seal-hero.bad {
  border-color: var(--danger);
  background: var(--danger-soft);
  color: var(--danger);
}

.axe-pattern-gate-app .seal-hero .ic {
  font-size: 38px;
  line-height: 1;
}

.axe-pattern-gate-app .seal-hero .t {
  margin-top: var(--space-2);
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
}

.axe-pattern-gate-app .seal-hero .d {
  margin-top: 4px;
  font-size: var(--text-xs);
  opacity: 0.9;
}

.axe-pattern-gate-app .signer-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
  color: var(--text-secondary);
  font-size: var(--text-sm);
}

.axe-pattern-gate-app details.fold {
  margin-bottom: var(--space-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
}

.axe-pattern-gate-app details.fold > summary {
  padding: var(--space-3) var(--space-4);
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  list-style: none;
}

.axe-pattern-gate-app details.fold > summary::-webkit-details-marker {
  display: none;
}

.axe-pattern-gate-app details.fold > summary::before {
  color: var(--text-tertiary);
  content: "▸ ";
}

.axe-pattern-gate-app details.fold[open] > summary::before {
  content: "▾ ";
}

.axe-pattern-gate-app details.fold > .fold-body {
  padding: 0 var(--space-4) var(--space-4);
}

.axe-pattern-gate-app .stamp-preview {
  max-height: 110px;
  padding: 6px;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--doc-paper);
}

.axe-pattern-gate-app .stamp-preview--compact {
  max-height: 44px;
  padding: 0;
  vertical-align: middle;
}

.axe-pattern-gate-app .diff {
  overflow-x: auto;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.65;
}

.axe-pattern-gate-app .diff .dline {
  padding: 0 12px;
  white-space: pre-wrap;
  word-break: break-all;
}

.axe-pattern-gate-app .diff .dadd {
  background: var(--success-soft);
}

.axe-pattern-gate-app .diff .dadd::before {
  color: var(--success);
  content: "+ ";
  font-weight: var(--weight-bold);
}

.axe-pattern-gate-app .diff .ddel {
  background: var(--danger-soft);
}

.axe-pattern-gate-app .diff .ddel::before {
  color: var(--danger);
  content: "- ";
  font-weight: var(--weight-bold);
}

.axe-pattern-gate-app .diff .dctx::before {
  content: "  ";
}

.axe-pattern-gate-app .diff .dhunk {
  padding: 2px 12px;
  background: var(--bg-subtle);
  color: var(--text-tertiary);
  font-size: 11px;
}

.axe-pattern-gate-app .sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  border: 0;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Responsive and print ------------------------------------------------ */

@media (max-width: 920px) {
  .axe-pattern-gate-app .gate-detail-layout {
    grid-template-columns: minmax(0, 1fr);
  }

  .axe-pattern-gate-app .gate-detail-layout > aside {
    position: static;
  }

  .axe-pattern-gate-app .axe-doc {
    width: 100%;
    min-height: auto;
    padding: 7mm 6mm;
  }

  .axe-pattern-gate-app .axe-doc-stage {
    padding: var(--space-3);
  }
}

@media (max-width: 720px) {
  .axe-pattern-gate-app .gate-resource-toolbar {
    grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
  }

  .axe-pattern-gate-app .gate-resource-toolbar > output {
    justify-self: start;
  }

  .axe-pattern-gate-app .gate-resource-toolbar > .actions {
    justify-content: stretch;
  }

  .axe-pattern-gate-app .gate-resource-toolbar > .actions > * {
    flex: 1 1 auto;
  }

  .axe-pattern-gate-app .gate-form-layout > fieldset {
    padding: var(--space-4);
  }

  .axe-pattern-gate-app .gate-form-layout > fieldset > div,
  .axe-pattern-gate-app .gate-copy-field > div {
    grid-template-columns: minmax(0, 1fr);
  }

  .axe-pattern-gate-app .gate-task-shell__body {
    padding: var(--space-4) var(--space-3) calc(var(--space-7) + 76px);
  }

  .axe-pattern-gate-app .gate-task-shell__footer > div {
    padding-inline: var(--space-3);
  }

  .axe-pattern-gate-app .container {
    padding: var(--space-4) var(--space-3) var(--space-7);
  }

  .axe-pattern-gate-app .gate-dashboard-status {
    grid-template-columns: minmax(0, 1fr);
  }

  .axe-pattern-gate-app .gate-dashboard-status > div + div {
    border-top: 1px solid var(--border-subtle);
    border-left: 0;
  }

  .axe-pattern-gate-app nav.top {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    height: auto;
    min-height: 52px;
    gap: var(--space-2) var(--space-3);
    padding: var(--space-2) var(--space-3);
  }

  .axe-pattern-gate-app nav.top .brand {
    grid-row: 1;
    grid-column: 1;
  }

  .axe-pattern-gate-app nav.top .right {
    grid-row: 1;
    grid-column: 3;
    justify-self: end;
  }

  .axe-pattern-gate-app nav.top .nav-menu {
    width: 100%;
    grid-row: 2;
    grid-column: 1 / -1;
  }

  .axe-pattern-gate-app nav.top .nav-menu:empty {
    display: none;
  }

  .axe-pattern-gate-app .navdrop-menu {
    right: 0;
    left: auto;
    max-width: calc(100vw - (2 * var(--space-3)));
  }

  .axe-pattern-gate-app .userchip .email-text {
    display: none;
  }

  .axe-pattern-gate-app .kv {
    grid-template-columns: 110px 1fr;
  }

  .axe-pattern-gate-app :where(table:not([class*="axe-"])) :where(th, td) {
    padding: 8px;
  }

  .axe-pattern-gate-app .diff {
    font-size: 11px;
  }

  .axe-pattern-gate-app .gate-action-note {
    width: 100%;
    margin-left: 0;
  }

  .axe-pattern-gate-app .gate-pdf-frame {
    height: 58vh;
    min-height: 360px;
  }

  .axe-pattern-gate-app table.reflow thead {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    border: 0;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  .axe-pattern-gate-app table.reflow tr {
    display: block;
    margin-bottom: var(--space-2);
    padding: var(--space-3);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
  }

  .axe-pattern-gate-app table.reflow td {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 6px 0;
    border: 0;
  }

  .axe-pattern-gate-app table.reflow td::before {
    color: var(--text-tertiary);
    content: attr(data-label);
    font-weight: var(--weight-semibold);
  }
}

@media (pointer: coarse) {
  .axe-pattern-gate-app .nav-menu a,
  .axe-pattern-gate-app .navdrop > summary,
  .axe-pattern-gate-app .chip,
  .axe-pattern-gate-app .axe-btn {
    min-height: 44px;
  }

  .axe-pattern-gate-app .nav-menu a,
  .axe-pattern-gate-app .navdrop > summary {
    display: inline-flex;
    align-items: center;
  }
}

@media (forced-colors: active) {
  .axe-pattern-gate-app :where(
    input:not([class*="axe-"]),
    select:not([class*="axe-"]),
    textarea:not([class*="axe-"])
  ):focus-visible,
  .axe-pattern-gate-app :where(input[type="file"]:not([class*="axe-"])):focus-visible {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
}

@media print {
  .axe-pattern-gate-app nav.top,
  .axe-pattern-gate-app .actions,
  .axe-pattern-gate-app .actbar,
  .axe-pattern-gate-app .gate-actbar-sticky,
  .axe-pattern-gate-app .gate-subnav,
  .axe-pattern-gate-app .gate-ai-chat,
  .axe-pattern-gate-app form,
  .axe-pattern-gate-app .footer,
  .axe-pattern-gate-app .gate-task-shell__footer,
  .axe-pattern-gate-app .notice,
  .axe-pattern-gate-app details.fold,
  .axe-pattern-gate-app .axe-btn {
    display: none !important;
  }

  .axe-pattern-gate-app {
    background: var(--doc-paper);
    color: var(--doc-ink);
    color-scheme: light;
  }

  .axe-pattern-gate-app .container {
    max-width: 100%;
    padding: 0;
  }

  .axe-pattern-gate-app .card,
  .axe-pattern-gate-app .docbody {
    padding: 0;
    border: 0;
    background: var(--doc-paper);
    color: var(--doc-ink);
    box-shadow: none;
  }

  .axe-pattern-gate-app .axe-doc-stage {
    padding: 0;
    background: var(--doc-paper);
  }

  .axe-pattern-gate-app .axe-doc {
    width: auto;
    min-height: auto;
    box-shadow: none;
  }
}

/* source: styles/components.css */
/* ============================================================
 * AXE Labs — component styles
 *
 * 모든 컴포넌트는 .axe- prefix.  Tailwind 의존 0.
 * CSS 변수로만 컬러·폰트·간격 참조 → light/dark 자동 전환.
 *
 * 그룹별 CSS 는 별도 파일 → 본 파일에서 @import.
 * 소비자는 components.css 만 import 해도 전 그룹 다 로드.
 * ============================================================ */

/* v2 component groups (Phase 1-14) — 그룹별 격리 + 한 곳 통합 */
/* Toast / Popover / Tooltip */
/* Select / Checkbox / Radio / Switch / FormField / Label */
/* Tabs / Sidebar / Breadcrumb / Sheet */
/* Stable 280 / bounded canvas / 280 application chrome */
/* Skeleton / Spinner / Avatar / Progress */
/* StatusLight / MetricCard / PipelineTable */
/* safe-area / tap highlight / .axe-tabular-nums / .axe-sticky-blur */
/* AgentExecutor / StreamingTable / MultiModalChatInput */
/* Phase 14 — gap fill */
/* DataTable / Pagination / Chart */
/* AlertDialog / Accordion / DropdownMenu */
/* EmptyState / ErrorBoundary */
/* Tree / Timeline / MasterDetailLayout */
/* MessageWithSources / TypingIndicator / StatusBanner / ResponsiveTabs */
/* Code / Section / Hero / Footer / Splitter / Callout left-bar modifier */
/* Phase 17 (D-ui-3 Phase 2) — 문서/인쇄 템플릿 */
/* .axe-doc IC Memo · LP letter (가로/세로, A4 @page, @media print) */
/* shiki ServerCodeBlock 팔레트 (--shiki-* → 디자인 토큰) */
/* Surface tones — Signature / Editorial / Console 스코프드 레이어 */
/* Landing / Authentication framework-neutral page patterns */
/* Gate authenticated/workflow/signing page pattern */
/* NOTE: tailwind-bridge.css 는 *opt-in* — 소비자가 Tailwind 쓸 때만 명시 import. */

/* ------- Logo ------- */
.axe-logo {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-brand, var(--font-clash));
  font-weight: var(--weight-medium);
  letter-spacing: -0.01em;
  color: var(--brand-claret);
  text-decoration: none;
  font-size: var(--text-lg);
  line-height: 1;
  white-space: nowrap;
}

.axe-logo--sm {
  font-size: var(--text-base);
}
.axe-logo--lg {
  font-size: var(--text-2xl);
}

/* ------- TopNav -------
 * v0.5 canonical markup — items 가 nav 직계 3-슬롯 (React = maud = jinja 공통):
 *   <nav class="axe-topnav" aria-label="Main navigation">
 *     <div class="axe-topnav__left"><a class="axe-logo" href="/">AXE Labs</a></div>
 *     <div class="axe-topnav__items"><!-- data-fade="left|right|both" = JS enhancement -->
 *       <a class="axe-topnav__item" aria-current="page" href="#principles">원칙</a>
 *       <a class="axe-topnav__item" href="#colors">Tokens</a>
 *     </div>
 *     <div class="axe-topnav__right"><!-- ThemeToggle 등 --></div>
 *   </nav>
 * 종전(v0.4)에는 items 가 __left 내부였음 — nav 직계 3-슬롯으로 평탄화.
 * 데스크톱 시각은 margin-left 보정으로 동일.
 * 모바일(≤767.98px, v0.6)에서는 같은 __items/__right 요소를 CSS 로 좌·우
 * 슬라이드 드로어로 재배치하고 ☰/⋯ 버튼이 토글한다 (아래 @media 블록 참조). */
.axe-topnav {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-3) var(--space-5);
  /* blur 커널 20px → 12px + 불투명도 92→95%: sticky 스크롤 경로에서 매 프레임
   * 재필터되는 비용을 줄임 (저사양 GPU 스크롤 jank 원인). 95% 불투명이라
   * 시각 차이는 거의 없음. */
  background: color-mix(in oklch, var(--bg-base) 95%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--border-subtle);
  /* 모바일 nav 가 참조 — 768px 미만에서 navbar 바로 아래에 fixed 로 펼침. */
  --axe-topnav-height: 56px;
  /* 바 높이를 토큰에 고정한다. 드로어(.axe-topnav__items/__right)·scrim·sub-nav
   * 가 모두 top:var(--axe-topnav-height) 로 anchor 하는데, 바의 자연 높이(컨텐츠
   * +패딩)가 토큰보다 작으면 그 차이가 바 아래·드로어 위 사이 여백으로 보인다
   * (모바일 ≈52px<56px → ~4px 띠, 2026-06-17 운영자 보고). min-height 로 바를
   * 정확히 토큰 높이로 맞춰 anchor 와 flush 하게 한다 (align-items:center 가
   * 컨텐츠 수직 중앙정렬 유지 — 데스크톱 바는 이미 ≈56px 라 시각 변화 없음). */
  min-height: var(--axe-topnav-height);
}
/* 로고 전용 슬롯 — 종전 flex:1 1 auto + overflow:hidden + gap space-6 삭제.
 * items 가 nav 직계로 빠지면서 left 는 더 이상 늘어나지 않는다. */
.axe-topnav__left {
  display: flex;
  align-items: center;
  min-width: 0;
  flex: 0 0 auto;
}
.axe-topnav__items {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  /* nav 직계 가변 슬롯 — right (테마 토글 등) 절대 가리지 않음 */
  flex: 1 1 0;
  min-width: 0;
  /* nav gap 24px(space-5) + 8px(space-2) = 32px — 종전 __left 내부 gap
   * space-6(32px) 보존 (데스크톱 시각 변화 0). */
  margin-left: var(--space-2);
  /* Tab focus 시 fade 영역 밖에 착지 */
  scroll-padding-inline: var(--space-6);
  /* items 많으면 가로 스크롤 */
  overflow-x: auto;
  scrollbar-width: none;       /* Firefox */
  -ms-overflow-style: none;    /* IE/old Edge */
}
.axe-topnav__items::-webkit-scrollbar {
  display: none;               /* Chrome/Safari */
}
/* fade gradient = "더 있다" 시각 힌트 — 실제 가려진 쪽에만.
 * data-fade 는 TopNavItems(client) 가 scroll/resize 마다 토글.
 * 무조건 mask 를 걸면 오버플로우 없는 데스크톱에서 마지막 항목
 * 끝 글자가 깎인다 (2026-06-10 회귀 — 재발 금지). */
.axe-topnav__items[data-fade="right"] {
  mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
  -webkit-mask-image: linear-gradient(to right, black calc(100% - 24px), transparent 100%);
}
.axe-topnav__items[data-fade="left"] {
  mask-image: linear-gradient(to left, black calc(100% - 24px), transparent 100%);
  -webkit-mask-image: linear-gradient(to left, black calc(100% - 24px), transparent 100%);
}
.axe-topnav__items[data-fade="both"] {
  mask-image: linear-gradient(
    to right,
    transparent 0,
    black 24px,
    black calc(100% - 24px),
    transparent 100%
  );
  -webkit-mask-image: linear-gradient(
    to right,
    transparent 0,
    black 24px,
    black calc(100% - 24px),
    transparent 100%
  );
}
.axe-topnav__item {
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-md);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  letter-spacing: 0.005em;
  color: var(--text-secondary);
  white-space: nowrap;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-topnav__item:hover {
  color: var(--text-primary);
  background: var(--bg-subtle);
}
/* 키보드 포커스 링 — brand · hamburger/kebab · drawer-close 와 동일한 어휘.
 * border 가 없는 텍스트 링크라 menu-trigger 의 box-shadow 링이 아니라 outline 을 쓴다.
 * border-radius 는 지정하지 않는다 — 이 요소는 이미 --radius-md 를 갖고 있어 outline 이
 * 그 곡률을 따른다. */
.axe-topnav__item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.axe-topnav__item[aria-current="page"],
.axe-topnav__item--active {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}
.axe-topnav__right {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: 0 0 auto;     /* 우선순위 — 절대 줄지 않음 */
  margin-left: var(--space-4);
}

/* ------- TopNav menu (NavMenu) -------
 * entity-selector + user-menu 통일 드롭다운. trigger(pill) + popover(absolute).
 * 같은 클래스로 두 용도가 픽셀 단위로 동일하게 보이게 한다. JS(NavMenu.tsx)는
 * open 토글 + click-outside + ↑↓/Esc 만; 표시는 100% CSS. */
.axe-topnav__menu {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
}
.axe-topnav__menu-trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  max-width: 220px;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-base);
  color: var(--text-secondary);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-topnav__menu-trigger:hover {
  color: var(--text-primary);
  border-color: var(--accent);
  background: var(--bg-subtle);
}
.axe-topnav__menu-trigger[data-state="open"] {
  color: var(--text-primary);
  border-color: var(--accent);
}
.axe-topnav__menu-trigger:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-topnav__menu-trigger[data-accent] {
  border-color: var(--accent);
  color: var(--text-primary);
}
.axe-topnav__menu-trigger-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.axe-topnav__menu-chevron {
  flex: 0 0 auto;
  color: var(--text-muted);
  transition: transform var(--duration-base) var(--ease-out);
}
.axe-topnav__menu-trigger[data-state="open"] .axe-topnav__menu-chevron {
  transform: rotate(180deg);
}

.axe-topnav__menu-popover {
  position: absolute;
  top: calc(100% + var(--space-2));
  /* 자동폭: trigger 폭 이상에서 시작해 내용에 맞춰 늘되 320px 상한. 종전 고정
   * min-width 200px 가 짧은 메뉴(계정 전환 등)에서 과하게 넓었음 (운영자 2026-06-17). */
  min-width: 100%;
  width: max-content;
  max-width: 320px;
  padding: var(--space-1);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  z-index: var(--z-overlay);
  animation: axe-topnav-menu-in var(--duration-fast) var(--ease-out);
}
.axe-topnav__menu-popover[data-align="right"] { right: 0; }
.axe-topnav__menu-popover[data-align="left"]  { left: 0; }

.axe-topnav__menu-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: none;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.4;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out);
}
.axe-topnav__menu-item:hover,
.axe-topnav__menu-item:focus-visible {
  outline: none;
  background: var(--bg-subtle);
  color: var(--text-primary);
}
.axe-topnav__menu-item--active {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
  background: var(--accent-soft);
}
.axe-topnav__menu-item-label {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.axe-topnav__menu-item-meta {
  flex: 0 0 auto;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.axe-topnav__menu-empty {
  padding: var(--space-3);
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-align: center;
}
.axe-topnav__menu-header {
  margin-bottom: var(--space-1);
  padding-bottom: var(--space-1);
  border-bottom: 1px solid var(--border-subtle);
}
.axe-topnav__menu-header-label {
  display: block;
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  white-space: nowrap;
}
.axe-topnav__menu-footer {
  margin-top: var(--space-1);
  padding-top: var(--space-1);
  border-top: 1px solid var(--border-subtle);
}
.axe-topnav__menu-item--danger {
  color: var(--danger);
}
.axe-topnav__menu-item--danger:hover,
.axe-topnav__menu-item--danger:focus-visible {
  background: var(--danger-soft);
  color: var(--danger);
}

@keyframes axe-topnav-menu-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .axe-topnav__menu-popover { animation: none; }
  .axe-topnav__menu-chevron { transition: none; }
}

/* ------- TopNav brand (home/brand 링크) -------
 * Logo 와 별개로 .axe-topnav__brand 만 붙여도 brand 식자(Clash) 로 렌더 가능.
 * Latin=Clash Display, 한글=Pretendard 폴백 (의도). */
.axe-topnav__brand {
  font-family: var(--font-brand, var(--font-clash));
  font-weight: var(--weight-medium);
  letter-spacing: -0.01em;
  color: var(--brand-claret);
  text-decoration: none;
  white-space: nowrap;
}
.axe-topnav__brand:hover {
  color: color-mix(in srgb, var(--brand-claret) 82%, var(--text-primary));
}
.axe-topnav__brand:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ------- Hamburger · Kebab 버튼 (모바일 전용 — 데스크톱 display:none) -------
 * v0.6: 모바일 2-드로어. 햄버거(좌)=items 드로어, kebab(우)=right 슬롯 드로어.
 *
 * 0.25.1 (운영자 2026-08-06): v0.10.1 의 **원형 아웃라인 칩**(36px · radius-full ·
 * border-subtle + bg-subtle)을 폐기한다. 0.24–0.25 에서 workspace 크롬이 정착시킨
 * 아이콘 버튼 어휘 — 보더·배경 없는 상자, radius 8, 색만으로 쉬는 상태를 말하고
 * hover 에서만 selected 배경이 서는 것(.axe-workspace-bar__icon-button ·
 * .axe-workspace-identity · .axe-workspace-entity 가 이미 그렇다) — 과 이 두 버튼만
 * 어긋나 있었다. 같은 제품의 공개 랜딩 바와 로그인 후 workspace 바가 한 화면 차이로
 * 다른 시대의 크롬을 그리던 것이 실제 증상이다.
 *
 * 치수는 rail 칩과 같은 규칙을 따른다: 정밀 포인터에서 28px 상자 + ::before(inset −8px)
 * 로 44px 실효 hit target, 터치(pointer: coarse)에서는 상자 자체가 44px 로 자란다.
 * 드로어 열림 지속 강조는 여전히 없다 (2026-06-18 '활성화 고착' 차단 존중 —
 * data-open bg 미부여). */
.axe-topnav__hamburger,
.axe-topnav__kebab {
  display: none;
  position: relative;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--text-secondary);
  background: transparent;
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out);
}
/* 44px 실효 hit target — 시각 28px 상자 밖으로 tap 영역 확장(레이아웃 불변). */
.axe-topnav__hamburger::before,
.axe-topnav__kebab::before {
  content: "";
  position: absolute;
  inset: -8px;
}
/* hover = 실제 포인터만(모바일 터치 sticky :hover 차단, 2026-06-18). selected 배경. */
@media (hover: hover) {
  .axe-topnav__hamburger:hover,
  .axe-topnav__kebab:hover {
    color: var(--text-primary);
    background: var(--bg-subtle);
  }
}
/* 터치는 상자 자체가 44px — rail 칩(.axe-workspace-identity 등)과 같은 규칙. */
@media (pointer: coarse) {
  .axe-topnav__hamburger,
  .axe-topnav__kebab {
    width: 44px;
    height: 44px;
  }
}
.axe-topnav__hamburger:focus-visible,
.axe-topnav__kebab:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.axe-topnav__kebab-icon {
  flex: 0 0 auto;
}

/* scrim — 양 드로어 공통 반투명 배경. nav 의 형제. 데스크톱 display:none. */
.axe-mobile-scrim {
  display: none;
}

.axe-topnav__drawer-close {
  display: none;
}

/* 햄버거 line — open 시 X 로 변형. transform 만 애니메이션 → GPU. */
.axe-hamburger-line {
  transform-origin: center;
  transition:
    transform var(--duration-base) var(--ease-out),
    opacity var(--duration-fast) var(--ease-out);
}
.axe-topnav__hamburger-icon[data-open="true"] .axe-hamburger-line--top {
  transform: translateY(6px) rotate(45deg);
}
.axe-topnav__hamburger-icon[data-open="true"] .axe-hamburger-line--mid {
  opacity: 0;
  transform: scaleX(0);
}
.axe-topnav__hamburger-icon[data-open="true"] .axe-hamburger-line--bot {
  transform: translateY(-6px) rotate(-45deg);
}

/* ------- 모바일 2-드로어 (≤767.98px) — v0.6 새 기본 (2026-06-17) -------
 * 단일 행 바 = [☰ 햄버거(좌)] [브랜드] [⋯ kebab(우, plain 36px)]. 인라인 items 와
 * 인라인 right 슬롯은 같은 요소를 CSS 로 고정 슬라이드 드로어로 재배치(중복
 * 렌더 없음). data-open="true" = 열림. 종전 2행 grid + .axe-mobile-nav 풀스크린
 * 오버레이 + .axe-topnav--drawer opt-in 은 폐지.
 *
 * 데스크톱(≥768px) inline 규칙은 이 @media 밖에 그대로 — 드로어 규칙은 모바일
 * 한정. 브레이크포인트 768px = docs.axelabs.ai (Nextra md) 와 동일. */
@media (max-width: 767.98px) {
  .axe-topnav {
    /* 단일 행 3-칼럼: [☰ 좌][브랜드 가운데][⋯ 우]. brand 를 뷰포트 가운데 고정
     * (drawer 는 position:fixed 라 grid flow 에서 빠짐 → 3 in-flow 항목만 칼럼 차지). */
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    /* 드로어 top = 단일 행 높이. (종전 92px 2행 폐지.) */
    --axe-topnav-height: 56px;
    /* ⚠️ backdrop-filter 는 position:fixed 자손의 containing block 을 만든다
     * (spec). 드로어(.axe-topnav__items/.axe-topnav__right) 가 nav 의 자식
     * 이므로, blur 를 켜두면 fixed 드로어가 viewport 가 아닌 56px nav 박스에
     * 갇혀 height 가 붕괴한다. 모바일에선 blur 제거 + 불투명 배경으로 같은
     * 시각을 유지하면서 containment trap 을 푼다. */
    background: var(--bg-base);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  .axe-topnav__hamburger {
    display: inline-flex;
    grid-column: 1;
    justify-self: start;
  }
  .axe-topnav__kebab {
    display: inline-flex;
    grid-column: 3;
    justify-self: end;
  }
  .axe-topnav__drawer-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    align-self: flex-end;
    width: 36px;
    height: 36px;
    margin-bottom: var(--space-1);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    background: transparent;
  }
  .axe-topnav__drawer-close:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
  }
  @media (hover: hover) {
    .axe-topnav__drawer-close:hover {
      background: var(--bg-subtle);
    }
  }
  /* 브랜드 슬롯 — 가운데 칼럼 = 뷰포트 중앙. */
  .axe-topnav__left {
    grid-column: 2;
    justify-self: center;
    margin-left: 0;
  }

  /* 좌 드로어 = nav items. 좌측 고정, translateX(-100%)→0 슬라이드. */
  .axe-topnav__items {
    position: fixed;
    top: var(--axe-topnav-height);
    left: 0;
    bottom: 0;
    width: min(280px, 80vw);
    margin: 0;
    padding: var(--space-3);
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-1);
    overflow-y: auto;
    overflow-x: hidden;             /* 세로 리스트 — 가로 fade 미적용 */
    overscroll-behavior: contain;
    background: var(--bg-base);
    border-right: 1px solid var(--border-subtle);
    box-shadow: var(--shadow-lg);
    z-index: var(--z-overlay);
    /* translate3d 로 GPU layer 강제 → 60fps (docs.axelabs.ai 패턴). */
    transform: translate3d(-100%, 0, 0);
    /* 닫힘 시 슬라이드아웃 완료 후 visibility:hidden → 키보드 tab·스크린리더에서
     * 제거 (transform 만으론 오프스크린 항목이 포커스·AT 에 남는 회귀). */
    visibility: hidden;
    transition:
      transform var(--duration-base) var(--ease-out),
      visibility 0s linear var(--duration-base);
    /* 세로 드로어엔 가로 오버플로우 없음 → data-fade mask 미적용. 안전상 명시 해제. */
    mask-image: none;
    -webkit-mask-image: none;
  }
  .axe-topnav__items[data-open="true"] {
    transform: translate3d(0, 0, 0);
    visibility: visible;
    transition: transform var(--duration-base) var(--ease-out);
  }
  /* 모바일 항목 = 세로 리스트. 탭타깃은 패딩(space-3 space-4 ≈ 44px 행)이 확보.
   * font-size 는 text-sm — 우 드로어(entity·계정 리스트 = text-sm)와 동일 스케일로
   * 통일 (종전 text-base 는 좌 드로어만 16px 라 우 드로어 14.4px 대비 떠 보였다,
   * 2026-06-17 운영자 보고). 드로어 타입 스케일: 헤더 text-xs / 항목 text-sm. */
  .axe-topnav__item {
    display: block;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    white-space: normal;
  }

  /* 우 드로어 = right 슬롯(entity+user NavMenu). 우측 고정, translateX(100%)→0. */
  .axe-topnav__right {
    position: fixed;
    top: var(--axe-topnav-height);
    right: 0;
    bottom: 0;
    width: min(300px, 85vw);
    margin: 0;
    padding: var(--space-4);
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--bg-base);
    border-left: 1px solid var(--border-subtle);
    box-shadow: var(--shadow-lg);
    z-index: var(--z-overlay);
    transform: translate3d(100%, 0, 0);
    visibility: hidden;
    transition:
      transform var(--duration-base) var(--ease-out),
      visibility 0s linear var(--duration-base);
  }
  .axe-topnav__right[data-open="true"] {
    transform: translate3d(0, 0, 0);
    visibility: visible;
    transition: transform var(--duration-base) var(--ease-out);
  }
  /* 우 드로어 안 NavMenu — 폭 채우고 trigger 도 full-width. popover 는
   * 드로어 스크롤 내 표시 (z-index 동일, 드로어보다 위 stacking). */
  .axe-topnav__right .axe-topnav__menu {
    display: flex;
    width: 100%;
  }
  .axe-topnav__right .axe-topnav__menu-trigger {
    width: 100%;
    max-width: none;
    justify-content: space-between;
  }
  .axe-topnav__right .axe-topnav__menu-popover {
    /* 드로어 안에서는 absolute float 대신 inline 펼침 — 스크롤 컨테이너
     * 클리핑·viewport 초과 점프 방지. */
    position: static;
    max-width: none;
    box-shadow: none;
    animation: none;
    margin-top: var(--space-1);
  }

  /* scrim — 양 드로어 공통. 바 아래(top) 전체 덮음. 패널보다 한 단계 아래. */
  .axe-mobile-scrim {
    display: block;
    position: fixed;
    inset: 0;
    /* scrim 은 nav 형제라 .axe-topnav 의 --axe-topnav-height 를 상속 못 함 → fallback 필수 */
    top: var(--axe-topnav-height, 56px);
    background: var(--bg-overlay);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--duration-base) var(--ease-out);
    z-index: calc(var(--z-overlay) - 1);
  }
  .axe-mobile-scrim[data-open="true"] {
    opacity: 1;
    pointer-events: auto;
  }
}

@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) {
  .axe-topnav__items,
  .axe-topnav__right,
  .axe-mobile-scrim,
  .axe-hamburger-line,
  .axe-topnav__kebab {
    transition: none;
  }
}

/* ------- Interactive affordance (공유 유틸리티) -------
 * 자체 hover/press 어휘가 없는 클릭 요소 — 내비 행, 표 링크, 카드, 아이콘 버튼 —
 * 에 다는 단일 공용 클래스. Blueprint 가 로컬 globals.css 에서 운용하던 규칙을
 * SSOT 로 승격(0.20.0). 근본 원인이던 "컴포넌트마다 inline style 로 그려서
 * :hover/:focus-visible/:active 를 표현 못 함" 을 한 클래스로 끝낸다.
 * 어휘는 .axe-topnav__item 미러 — 보더·그림자 없이 밀도 유지, active 는
 * accent-soft 배경으로 hover 의 gray 와 구분한다.
 * 자체 시각 어휘를 가진 primitive(.axe-btn·.axe-seg__btn 등)에는 겹쳐 쓰지 않는다.
 * 아래 Button 규칙보다 앞에 두어 dual-class 시 컴포넌트 어휘가 이긴다. */
.axe-interactive {
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    color var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .axe-interactive:hover {
    color: var(--text-primary);
    background-color: var(--bg-subtle);
  }
}

/* 키보드 포커스 표식 — :focus-visible 만이라 마우스 클릭에는 안 뜬다. 톤은 accent
 * 50% 아웃라인: 밀도 높은 행에서 2px --ring 이 "중복 테두리"로 보이던 회귀를 피한
 * 값이다. 포커스 모달리티를 더 좁히려는 소비자(예 Blueprint 의 html[data-kbnav])는
 * 자기 층에서 더 높은 명시도로 재정의한다 — 라이브러리 기본은 링을 준다. */
.axe-interactive:focus-visible {
  outline: 1.5px solid color-mix(in srgb, var(--accent) 50%, transparent);
  outline-offset: 2px;
}

.axe-interactive:active {
  transform: scale(0.97);
}

.axe-interactive[aria-current="page"],
.axe-interactive[aria-selected="true"],
.axe-interactive[data-active="true"],
.axe-interactive--active {
  color: var(--accent);
  font-weight: var(--weight-medium);
  background-color: var(--accent-soft);
}

.axe-interactive[aria-current="page"]:hover,
.axe-interactive[aria-selected="true"]:hover,
.axe-interactive[data-active="true"]:hover,
.axe-interactive--active:hover {
  color: var(--accent);
  background-color: var(--accent-soft);
}

@media (prefers-reduced-motion: reduce) {
  .axe-interactive:active {
    transform: none;
  }
}

/* ------- Inline link (공유 재료) -------
 * 산문 **밖**에서도 쓰는 인라인 링크 한 겹. `.axe-prose a` 는 자손 셀렉터라
 * `.axe-prose` 안에서만 서고, 캔버스에 그냥 놓인 <a>(되돌아가기 · 각주 · 고지
 * 안 링크)에는 아무 어휘도 없었다 — 그래서 소비자 넷이 클래스 없는 <a> 를
 * 그대로 두었다. 이 클래스가 그 자리를 갖는다: 색 축은 `.axe-prose a` 와 같은
 * accent 이고(같은 제품의 링크가 자리에 따라 다른 색이면 그것은 두 제품이다)
 * 밑줄은 링크임을 색에만 의존하지 않고 알리는 어포던스라 항상 켜 둔다.
 *
 * `:visited` 를 따로 물들이지 않는다 — UI 표면의 링크는 문서 열람 이력이 아니라
 * 현재 상태를 가리키는 이동 수단이고, 방문색이 붙으면 같은 자리의 두 사용자가
 * 다른 색을 본다.
 *
 * 포커스는 outline 이다. `--ring` 은 box-shadow 토큰이라 (a) 여러 줄로 감기는
 * 인라인 조각마다 halo 가 그려져 이웃 줄의 글자를 덮고 (b) forced-colors 에서
 * 그림자가 그려지지 않아 표식이 통째로 사라진다. 값은 킷의 기존 인라인 링크
 * 포커스(page-patterns 의 auth 각주 링크)와 같은 2px accent + 2px offset 이다. */
.axe-link {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
  text-decoration-skip-ink: auto;
  border-radius: var(--radius-sm);
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-link:visited {
  color: var(--accent);
}

@media (hover: hover) and (pointer: fine) {
  .axe-link:hover {
    color: var(--accent-hover);
  }
}

.axe-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

@media (forced-colors: active) {
  /* 강제색 모드는 author 색을 시스템 팔레트로 갈아끼운다. 링크는 전용 시스템
   * 색(LinkText)이 있으므로 그것을 명시해 본문(CanvasText)과 갈린 채로 남긴다. */
  .axe-link {
    color: LinkText;
  }
  .axe-link:focus-visible {
    outline-color: LinkText;
  }
}

/* ------- Button ------- */
.axe-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  height: 36px;
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  letter-spacing: 0;
  line-height: 1;
  cursor: pointer;
  transition:
    background var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out);
  white-space: nowrap;
  user-select: none;
  border: 1px solid transparent;
}
.axe-btn:disabled,
.axe-btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
}
.axe-btn:active:not(:disabled) {
  transform: scale(0.98);
}

.axe-btn--sm {
  height: 28px;
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
}
.axe-btn--lg {
  height: 44px;
  padding: 0 var(--space-5);
  font-size: var(--text-base);
}

.axe-btn--primary {
  background: var(--cta);
  color: var(--cta-fg);
  font-weight: var(--weight-semibold);
}
/* lift/hover surface는 실제 hover 가능한 fine pointer에서만. touch tap 뒤 :hover가
 * sticky하게 남아 버튼이 떠 보이는 것을 막고, touch는 :active press feedback만 쓴다. */
@media (hover: hover) and (pointer: fine) {
  .axe-btn--primary:hover:not(:disabled) {
    background: var(--cta-hover);
    transform: translateY(-1px);
    box-shadow: var(--shadow-sm);
  }
}
.axe-btn--primary:active:not(:disabled) {
  transform: scale(0.98); /* hover lift 보다 우선 — 누름 피드백 */
  box-shadow: none;
}

.axe-btn--secondary {
  background: var(--bg-elevated);
  border-color: var(--border-control, var(--border-strong));
  color: var(--text-primary);
}
.axe-btn--secondary:hover:not(:disabled) {
  border-color: var(--border-control-hover, var(--border-control));
  background: var(--bg-subtle);
}

.axe-btn--ghost {
  background: transparent;
  color: var(--text-secondary);
}
.axe-btn--ghost:hover:not(:disabled) {
  background: var(--bg-subtle);
  color: var(--text-primary);
}

.axe-btn--danger {
  background: var(--danger);
  color: #fff;
}
.axe-btn--danger:hover:not(:disabled) {
  filter: brightness(0.95);
}

/* loading 상태 (Button loading prop) — spinner 가 children 앞에 렌더됨 */
.axe-btn--loading {
  pointer-events: none;
}
.axe-btn__icon {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}

/* ------- Seg (segmented control) -------
 * VariantSwitcher · DocSeg 등이 inline style 로 2번 재발명하던 패턴의 SSOT.
 * React <Seg> + CSS-only (maud/jinja) 양쪽에서 동일 markup:
 *   <div class="axe-seg" role="group" aria-label="...">
 *     <button class="axe-seg__btn" aria-pressed="true">A</button>
 *     <button class="axe-seg__btn">B</button>
 *   </div>
 */
.axe-seg {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}
.axe-seg__btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  padding: 0 var(--space-3);
  height: 28px;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  /* spring snap — transform/색만 변경 (compositor-safe) */
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-base) var(--ease-spring);
}
.axe-seg__btn:hover:not([aria-pressed="true"]) {
  color: var(--text-primary);
}
.axe-seg__btn:active {
  transform: scale(0.96);
}
.axe-seg__btn[aria-pressed="true"],
.axe-seg__btn--active {
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
  border-color: var(--border-subtle);
  box-shadow: var(--shadow-xs);
}
.axe-seg--sm .axe-seg__btn {
  height: 24px;
  padding: 0 var(--space-2);
}

/* ------- ToggleGroup (axe-toggle-group__*) -------
 * Seg 와 같은 시각 family(pill 묶음)이나 의미가 다르다: Seg = 단일 필수 선택
 * (항상 1개 pressed), ToggleGroup = 다중 토글 또는 해제 가능한 단일 (0~N개
 * pressed) — 정렬/서식 툴바·필터 칩. React <ToggleGroup> + CSS-only
 * (maud/jinja) 양쪽 동일 markup:
 *   <div class="axe-toggle-group" role="group" aria-label="...">
 *     <button class="axe-toggle-group__btn" aria-pressed="true">B</button>
 *     <button class="axe-toggle-group__btn">I</button>
 *   </div>
 */
.axe-toggle-group {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}
.axe-toggle-group__btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  padding: 0 var(--space-3);
  height: 28px;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-base) var(--ease-spring);
}
.axe-toggle-group__btn:hover:not([aria-pressed="true"]):not(:disabled) {
  color: var(--text-primary);
}
.axe-toggle-group__btn:active:not(:disabled) {
  transform: scale(0.96);
}
.axe-toggle-group__btn[aria-pressed="true"] {
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
  border-color: var(--border-subtle);
  box-shadow: var(--shadow-xs);
}
.axe-toggle-group__btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-toggle-group--sm .axe-toggle-group__btn {
  height: 24px;
  min-width: 24px;
  padding: 0 var(--space-2);
}

/* ------- Toggle (axe-toggle) — standalone 단일 두-상태 누름 -------
 * .axe-toggle-group__btn 의 standalone 변형 — 묶음 컨테이너가 없으니
 * 자체 border/bg 를 들고 다닌다. pressed = aria-pressed="true". 동일 motion.
 *   <button class="axe-toggle" aria-pressed="true">★</button> */
.axe-toggle {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  padding: 0 var(--space-3);
  height: 28px;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--text-secondary);
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  cursor: pointer;
  white-space: nowrap;
  transition:
    background var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-base) var(--ease-spring);
}
.axe-toggle:hover:not([aria-pressed="true"]):not(:disabled) {
  color: var(--text-primary);
}
.axe-toggle:active:not(:disabled) {
  transform: scale(0.96);
}
.axe-toggle[aria-pressed="true"] {
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
  border-color: var(--border-default);
  box-shadow: var(--shadow-xs);
}
.axe-toggle:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.axe-toggle--sm {
  height: 24px;
  min-width: 24px;
  padding: 0 var(--space-2);
}

/* ------- Skip link (AppShell 첫 child) -------
 * 평소 화면 밖 — 키보드 포커스 시에만 표시. */
.axe-skip-link {
  position: fixed;
  top: var(--space-3);
  left: var(--space-3);
  z-index: calc(var(--z-toast) + 1);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--cta);
  color: var(--cta-fg);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  /* The shadow belongs to the focused state, not the parked one. Parked, this
   * link sits above the viewport — but a shadow is drawn outside the box, so
   * --shadow-lg's blur bled back down and left a grey smudge in the top-left
   * corner of every @axe/ui surface (measured 2026-08-06 on index). */
  transform: translateY(calc(-100% - var(--space-5)));
  transition: transform var(--duration-base) var(--ease-out);
}
.axe-skip-link:focus-visible {
  box-shadow: var(--shadow-lg);
  transform: translateY(0);
}

/* ------- Input ------- */
.axe-input {
  display: inline-flex;
  align-items: center;
  width: 100%;
  height: 36px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-control, var(--border-strong));
  background: var(--bg-elevated);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.4;
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-input::placeholder {
  color: var(--text-muted);
}
.axe-input:hover {
  border-color: var(--border-control-hover, var(--border-control));
}
.axe-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}

.axe-input--lg {
  height: 44px;
  font-size: var(--text-base);
}
.axe-input--textarea {
  height: auto;
  min-height: 80px;
  padding: var(--space-3);
  line-height: var(--leading-body);
  resize: vertical;
}

/* ------- Card ------- */
.axe-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  box-shadow: var(--shadow-xs);
  transition:
    border-color var(--duration-base) var(--ease-out),
    box-shadow var(--duration-base) var(--ease-out),
    transform var(--duration-base) var(--ease-out);
}
.axe-card--interactive {
  cursor: pointer;
}
/* hover = lift (이전의 full-accent 보더 스냅 대체 — transform/shadow 만
 * 변경이라 compositor-only, 레이아웃 무영향) */
.axe-card--interactive:hover {
  border-color: var(--border-strong);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.axe-card__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-heading);
  line-height: var(--leading-heading);
  color: var(--text-primary);
  margin-bottom: var(--space-2);
}
.axe-card__body {
  color: var(--text-secondary);
  font-size: var(--text-sm);
  line-height: var(--leading-body);
}

/* ------- Callout ------- */
.axe-callout {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid;
  font-size: var(--text-sm);
  line-height: var(--leading-body);
}
.axe-callout__icon {
  flex-shrink: 0;
  font-size: var(--text-base);
  line-height: var(--leading-body);
}
.axe-callout__content {
  flex: 1;
  min-width: 0;
}
.axe-callout__title {
  font-weight: var(--weight-semibold);
  margin-bottom: var(--space-1);
}

.axe-callout--info {
  background: var(--info-soft);
  border-color: var(--info);
  color: var(--text-primary);
}
.axe-callout--info .axe-callout__icon {
  color: var(--info);
}

.axe-callout--success {
  background: var(--success-soft);
  border-color: var(--success);
  color: var(--text-primary);
}
.axe-callout--success .axe-callout__icon {
  color: var(--success);
}

.axe-callout--warning {
  background: var(--warning-soft);
  border-color: var(--warning);
  color: var(--text-primary);
}
.axe-callout--warning .axe-callout__icon {
  color: var(--warning);
}

.axe-callout--danger {
  background: var(--danger-soft);
  border-color: var(--danger);
  color: var(--text-primary);
}
.axe-callout--danger .axe-callout__icon {
  color: var(--danger);
}

.axe-callout--note {
  background: var(--bg-subtle);
  border-color: var(--border-subtle);
  color: var(--text-secondary);
}
.axe-callout--note .axe-callout__icon {
  color: var(--text-tertiary);
}

/* ------- Badge ------- */
.axe-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-wide);
  line-height: 1.4;
  background: var(--bg-subtle);
  color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
}
.axe-badge--accent {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: transparent;
}
.axe-badge--success {
  background: var(--success-soft);
  color: var(--success);
  border-color: transparent;
}
.axe-badge--warning {
  background: var(--warning-soft);
  color: var(--warning);
  border-color: transparent;
}
.axe-badge--danger {
  background: var(--danger-soft);
  color: var(--danger);
  border-color: transparent;
}
.axe-badge--info {
  background: var(--info-soft);
  color: var(--info);
  border-color: transparent;
}

/* ------- CodeBlock ------- */
.axe-codeblock {
  position: relative;
  min-width: 0;
  max-width: 100%;
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.axe-codeblock__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  background: color-mix(in oklch, var(--bg-subtle) 80%, var(--bg-base));
  border-bottom: 1px solid var(--border-subtle);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
}
.axe-codeblock__lang {
  text-transform: lowercase;
  letter-spacing: 0.04em;
}
.axe-codeblock__copy {
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-codeblock__copy:hover {
  color: var(--text-primary);
  background: var(--bg-base);
}
.axe-codeblock__pre {
  margin: 0;
  padding: var(--space-4);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--leading-code);
  color: var(--text-primary);
  /* 한글·ASCII 박스 정렬 핵심:
   * 1) Sarasa Term K / D2Coding 이 한글을 정확히 2× 너비로 렌더
   * 2) keep-all 해제 — 코드는 그대로 보여줌 */
  word-break: normal;
  white-space: pre;
  tab-size: 4;
  font-variant-ligatures: contextual;
  font-feature-settings: "calt" 1;
}
.axe-codeblock__pre code {
  font-family: inherit;
  font-size: inherit;
}

/* 인라인 code */
.axe-code-inline,
:not(pre) > code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  padding: 0.125em 0.4em;
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  word-break: break-all;
}

/* ------- Table ------- */
.axe-table-wrap {
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-elevated);
}
.axe-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  font-variant-numeric: tabular-nums;
}
.axe-table thead th {
  text-align: left;
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-subtle);
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}
.axe-table tbody td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-primary);
  vertical-align: top;
}
.axe-table tbody tr:last-child td {
  border-bottom: 0;
}
.axe-table tbody tr:hover td {
  background: var(--bg-subtle);
}

/* ------- Prose (마크다운 본문 래퍼) -------
 * 단일 클래스로 임의 마크다운 트리에 prose 스타일 부여.
 * docs.axelabs.ai 처럼 정보 밀도 높은 페이지에 .axe-prose 한 줄로. */
.axe-prose {
  max-width: var(--prose-max);
  color: var(--text-primary);
  font-size: var(--text-base);
  line-height: var(--leading-body);
}

.axe-prose > * + * {
  margin-top: var(--space-4);
}
.axe-prose > h1 + *,
.axe-prose > h2 + *,
.axe-prose > h3 + * {
  margin-top: var(--space-3);
}
.axe-prose > * + h2 {
  margin-top: var(--space-7);
}
.axe-prose > * + h3 {
  margin-top: var(--space-6);
}

.axe-prose h1,
.axe-prose h2,
.axe-prose h3,
.axe-prose h4,
.axe-prose h5,
.axe-prose h6 {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-heading);
  color: var(--text-primary);
}
.axe-prose h1 {
  font-size: var(--text-4xl);
  line-height: var(--leading-tight);
}
.axe-prose h2 {
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border-subtle);
}
.axe-prose h3 {
  font-size: var(--text-xl);
  line-height: var(--leading-heading);
}
.axe-prose h4 {
  font-size: var(--text-lg);
  line-height: var(--leading-heading);
}
.axe-prose h5,
.axe-prose h6 {
  font-size: var(--text-base);
  line-height: var(--leading-heading);
}

.axe-prose p {
  font-size: var(--text-base);
  line-height: var(--leading-body);
  letter-spacing: 0;
  color: var(--text-primary);
}

.axe-prose a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color var(--duration-fast) var(--ease-out);
}
.axe-prose a:hover {
  color: var(--accent-hover);
}

.axe-prose ul,
.axe-prose ol {
  padding-left: var(--space-5);
  line-height: var(--leading-body);
}
.axe-prose ul {
  list-style: disc;
}
.axe-prose ol {
  list-style: decimal;
}
.axe-prose li::marker {
  color: var(--text-tertiary);
}
.axe-prose li + li {
  margin-top: var(--space-1);
}
.axe-prose li p {
  margin-top: 0;
}
.axe-prose li > ul,
.axe-prose li > ol {
  margin-top: var(--space-1);
}

.axe-prose blockquote {
  border-left: 3px solid var(--border-strong);
  padding: var(--space-2) var(--space-4);
  color: var(--text-secondary);
  font-style: italic;
}

.axe-prose hr {
  border: 0;
  height: 1px;
  background: var(--border-subtle);
  margin: var(--space-6) 0;
}

.axe-prose strong {
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.axe-prose img {
  border-radius: var(--radius-md);
  border: 1px solid var(--border-subtle);
}

/* prose 안의 표·코드블록은 위에서 정의한 클래스 스타일을 그대로 받도록
 * 동일 셀렉터 사용 */
.axe-prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.axe-prose table thead th {
  text-align: left;
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  padding: var(--space-2) var(--space-3);
  background: var(--bg-subtle);
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
}
.axe-prose table tbody td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: top;
}
.axe-prose table tbody tr:last-child td {
  border-bottom: 0;
}

.axe-prose pre {
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--leading-code);
  word-break: normal;
  white-space: pre;
  tab-size: 4;
}
.axe-prose pre code {
  background: transparent;
  border: 0;
  padding: 0;
  font-size: inherit;
}

/* ------- Chat — AI-first ------- */
.axe-chat-input {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--border-control, var(--border-strong));
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-chat-input:focus-within {
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.axe-chat-input__textarea {
  width: 100%;
  border: 0;
  background: transparent;
  resize: none;
  outline: none;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  min-height: 1.5em;
  max-height: 12em;
}
.axe-chat-input__textarea::placeholder {
  color: var(--text-muted);
}
.axe-chat-input__toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.axe-chat-input__hint {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  font-family: var(--font-mono);
}

/* MessageBubble */
.axe-message {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-4) 0;
}
.axe-message__avatar {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-full);
  /* gray-9 = Radix scale 의 "solid bg" tier. avatar 같은 UI 마크용. */
  background: var(--gray-9);
  color: var(--bg-base);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}
.axe-message--user .axe-message__avatar {
  background: var(--accent);
  color: var(--accent-fg);
}
.axe-message__body {
  flex: 1;
  min-width: 0;
  color: var(--text-primary);
  font-size: var(--text-base);
  line-height: var(--leading-body);
}
.axe-message__role {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  margin-bottom: var(--space-1);
}
.axe-message__content > * + * {
  margin-top: var(--space-3);
}

/* StreamingMarkdown — pulse cursor */
.axe-stream-cursor {
  display: inline-block;
  width: 0.5em;
  height: 1em;
  background: var(--accent);
  margin-left: 2px;
  vertical-align: text-bottom;
  animation: axe-blink 1s steps(2, end) infinite;
}
@keyframes axe-blink {
  0%, 50% {
    opacity: 1;
  }
  50.01%, 100% {
    opacity: 0;
  }
}

/* ToolCallCard */
.axe-toolcall {
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--leading-code);
  overflow: hidden;
}
.axe-toolcall__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  user-select: none;
  background: color-mix(in oklch, var(--bg-subtle) 80%, var(--bg-base));
  border-bottom: 1px solid transparent;
  transition: background var(--duration-fast) var(--ease-out);
}
.axe-toolcall__header:hover {
  background: color-mix(in oklch, var(--bg-subtle) 60%, var(--bg-base));
}
.axe-toolcall[data-open="true"] .axe-toolcall__header {
  border-bottom-color: var(--border-subtle);
}
.axe-toolcall__name {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--accent);
  font-weight: var(--weight-semibold);
}
.axe-toolcall__status {
  color: var(--text-tertiary);
  font-size: var(--text-xs);
}
.axe-toolcall__chevron {
  color: var(--text-tertiary);
  transition: transform var(--duration-fast) var(--ease-out);
}
.axe-toolcall[data-open="true"] .axe-toolcall__chevron {
  transform: rotate(90deg);
}
.axe-toolcall__body {
  padding: var(--space-3);
  color: var(--text-primary);
  white-space: pre-wrap;
  word-break: normal;
  overflow-x: auto;
}

/* CommandPalette (⌘K) */
.axe-cmdk-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--bg-overlay);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
}
.axe-cmdk {
  width: min(560px, 92vw);
  max-height: calc(100dvh - 2 * var(--space-4));
  display: flex;
  flex-direction: column;
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xl); /* 큰 floating surface = 16px (radius 위계) */
  box-shadow: var(--shadow-xl);
  overflow: hidden;
}
.axe-cmdk__search-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  border-bottom: 1px solid var(--border-subtle);
  transition:
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
}
.axe-cmdk__search-row:focus-within {
  border-bottom-color: var(--accent);
  box-shadow: inset 0 -1px 0 var(--accent);
}
.axe-cmdk__input {
  width: 100%;
  padding: var(--space-4);
  border: 0;
  outline: none;
  background: transparent;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-base);
}
.axe-cmdk__input::placeholder {
  color: var(--text-muted);
}
.axe-cmdk__close {
  min-width: 38px;
  min-height: 30px;
  margin-right: var(--space-3);
  padding: 0 var(--space-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}
.axe-cmdk__close:hover {
  border-color: var(--border-strong);
  color: var(--text-primary);
}
.axe-cmdk__list {
  min-height: 0;
  max-height: min(400px, calc(100dvh - 8rem));
  overflow-y: auto;
  padding: var(--space-2);
}
.axe-cmdk__group {
  margin-bottom: var(--space-2);
}
.axe-cmdk__group-label {
  font-family: var(--font-display);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-widest);
  color: var(--text-tertiary);
  padding: var(--space-2) var(--space-3);
}
.axe-cmdk__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-out);
}
.axe-cmdk__item[aria-selected="true"],
.axe-cmdk__item:hover {
  background: var(--bg-subtle);
}
.axe-cmdk__item-meta {
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}
.axe-cmdk__empty {
  padding: var(--space-6);
  text-align: center;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* kbd 키 표기 */
.axe-kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5em;
  padding: 0 0.4em;
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
  border: 1px solid var(--border-subtle);
  border-bottom-width: 2px;
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: 0.85em;
  line-height: 1.6;
}

/* ============================================================
 * Dialog (Modal) — Radix Dialog 위 styling
 *
 *  size variant: sm 440 / md 560 / lg 720 / xl 960 / full 100vw
 *  data-state="open|closed" 으로 Radix 가 트랜지션 트리거.
 *  prefers-reduced-motion 존중.
 * ============================================================ */
/* Sheet 와 같은 불변식: overlay 층(--z-overlay) > sticky chrome 층(--z-sticky),
 * overlay 와 content 는 동률이고 순서는 portal DOM 이 정한다. raw 50/51 이던
 * 값이 sticky topbar·rail 아래로 렌더되던 원인 — 근거 주석은
 * styles/layout.css 의 .axe-sheet__overlay 위. */
.axe-dialog__overlay {
  position: fixed;
  inset: 0;
  background: var(--bg-overlay);
  backdrop-filter: blur(2px);
  z-index: var(--z-overlay);
  animation: axe-dialog-overlay-in 160ms ease-out;
}
.axe-dialog__overlay[data-state="closed"] {
  animation: axe-dialog-overlay-out 120ms ease-in forwards;
}

.axe-dialog__content {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(100vw - 2 * var(--space-4));
  max-height: calc(100vh - 2 * var(--space-4));
  max-height: calc(100dvh - 2 * var(--space-4));
  overflow: auto;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl); /* 큰 floating surface = 16px (radius 위계) */
  box-shadow: var(--shadow-xl);
  padding: var(--space-6);
  z-index: var(--z-overlay); /* 위 불변식 — overlay 와 동률, portal 순서로 위 */
  animation: axe-dialog-content-in 180ms cubic-bezier(0.16, 1, 0.3, 1);
}
.axe-dialog__content[data-state="closed"] {
  animation: axe-dialog-content-out 140ms ease-in forwards;
}
.axe-dialog__content:focus { outline: none; }

.axe-dialog__content--sm   { max-width: 440px; }
.axe-dialog__content--md   { max-width: 560px; }
.axe-dialog__content--lg   { max-width: 720px; }
.axe-dialog__content--xl   { max-width: 960px; }
.axe-dialog__content--full {
  width: 100vw;
  max-width: 100vw;
  height: 100vh;
  height: 100dvh;
  max-height: 100dvh;
  top: 0;
  left: 0;
  transform: none;
  border-radius: 0;
}

.axe-dialog__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
  padding-right: var(--space-8); /* close X 자리 */
}

.axe-dialog__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: var(--text-lg);
  line-height: 1.3;
  color: var(--text-primary);
  margin: 0;
}

.axe-dialog__description {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--text-secondary);
  margin: 0;
}

.axe-dialog__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
}

@keyframes axe-dialog-overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes axe-dialog-overlay-out {
  to { opacity: 0; }
}
@keyframes axe-dialog-content-in {
  from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes axe-dialog-content-out {
  to { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
}

@media (prefers-reduced-motion: reduce) {
  .axe-dialog__overlay,
  .axe-dialog__content,
  .axe-dialog__overlay[data-state="closed"],
  .axe-dialog__content[data-state="closed"] {
    animation: none;
  }
}

/* @axe/ui generated compatibility profile: legacy-light.
 * Unsupported browsers degrade to one canonical light mode, even when
 * a dark class/data attribute or dark OS preference is present. */
@supports not (color: light-dark(#000, #fff)) {
  :root,
  [data-theme="dark"],
  .dark,
  [data-theme="light"],
  .light,
  :root:not([data-theme="light"]):not(.light) {
    color-scheme: light;
    --brand-claret: #821f3b;
    --palette-green: #00523f;
    --palette-blue: #104a70;
    --palette-orange: #9b562e;
    --gray-1: #f7f7f6;
    --gray-2: #f3f3f2;
    --gray-3: #efefee;
    --gray-4: #e9e9e8;
    --gray-5: #e4e4e2;
    --gray-6: #dcdcd9;
    --gray-7: #d5d5d2;
    --gray-8: #b8b8b4;
    --gray-9: #8a8a86;
    --gray-10: #686865;
    --gray-11: #4b4b48;
    --gray-12: #20201e;
    --bg-elevated: #ffffff;
    --bg-overlay: rgb(32 32 30 / 0.55);
    --border-subtle: rgb(32 32 30 / 0.12);
    --border-default: rgb(32 32 30 / 0.17);
    --border-strong: rgb(32 32 30 / 0.29);
    --border-control: rgb(32 32 30 / 0.48);
    --border-control-hover: #8a8a86;
    --accent-hover: #0c3c5b;
    --accent-fg: #ffffff;
    --accent-soft: rgb(16 74 112 / 0.10);
    --danger: #c4321f;
    --success-soft: #e5f1ed;
    --warning-soft: #f4e9e1;
    --danger-soft: #fbe7e2;
    --info-soft: #e7f0f5;
    --shadow-xs: 0 1px 2px rgb(32 32 30 / 0.05);
    --shadow-sm: 0 1px 2px rgb(32 32 30 / 0.05), 0 2px 6px -1px rgb(32 32 30 / 0.05);
    --shadow-md: 0 2px 4px rgb(32 32 30 / 0.04), 0 8px 20px -6px rgb(32 32 30 / 0.10);
    --shadow-lg: 0 4px 8px rgb(32 32 30 / 0.05), 0 20px 48px -12px rgb(32 32 30 / 0.16);
    --shadow-xl: 0 8px 16px rgb(32 32 30 / 0.06), 0 32px 80px -16px rgb(32 32 30 / 0.22);
  }
}
