⋯ 2 lines Show the 2 lines above this hunk @@ -3,7 +3,7 @@3 3 < head > 4 4 < meta charset = "utf-8" > 5 5 < meta name = "viewport" content = "width=device-width, initial-scale=1" > 6 - < meta name = "color-scheme" content = "light" > 6 + < meta name = "color-scheme" content = "light dark " > 7 7 < meta name = "description" content = "@yield('description', 'Postline is a clean personal workspace for social publishing.')" > 8 8 < title > @ yield ( 'title' , 'Postline' ) < / title > 9 9 < link rel = "icon" href = "/favicon.svg" type = "image/svg+xml" > ⋯ 8 lines Show the 8 lines above this hunk @@ -18,15 +18,20 @@18 18 } ) ( ) 19 19 < / script > 20 20 < script > 21 + / / Theme bootstrap — runs before paint to avoid a flash . Stored 22 + / / preference is 'light' | 'dark' | 'system' ( default system ) . 21 23 ; ( ( ) = > { 22 - document . documentElement . setAttribute ( 'data-theme' , 'light' ) 23 - document . documentElement . classList . remove ( 'dark' ) 24 + const root = document . documentElement 24 25 try { 25 - window . localStorage ? . setItem ( 'theme' , ' light ' ) 26 + const stored = window . localStorage ? . getItem ( 'theme' ) | | ' system ' 27 + const dark = stored = = = 'dark' | | ( stored = = = 'system' & & window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ) 28 + root . classList . toggle ( 'dark' , dark ) 29 + root . setAttribute ( 'data-theme' , dark ? 'dark' : 'light' ) 30 + 26 31 const sidebarCollapsed = window . localStorage ? . getItem ( 'postline.sidebar.collapsed' ) = = = 'true' 27 - document . documentElement . classList . toggle ( 'postline-sidebar-collapsed' , sidebarCollapsed ) 28 - document . documentElement . dataset . stxSidebarCollapsed = sidebarCollapsed ? 'true' : 'false' 29 - document . documentElement . style . setProperty ( '--postline-sidebar-width' , sidebarCollapsed ? '0px' : '286px' ) 32 + root . classList . toggle ( 'postline-sidebar-collapsed' , sidebarCollapsed ) 33 + root . dataset . stxSidebarCollapsed = sidebarCollapsed ? 'true' : 'false' 34 + root . style . setProperty ( '--postline-sidebar-width' , sidebarCollapsed ? '0px' : '286px' ) 30 35 } catch { } 31 36 } ) ( ) 32 37 < / script > ⋯ 4 lines Show the 4 lines above this hunk @@ -37,6 +42,97 @@37 42 background : # f3f3f1 ; 38 43 } 39 44 45 + html . dark { 46 + color - scheme : dark ; 47 + background : # 0 a0a0c ; 48 + } 49 + 50 + / * 51 + * Dark theme — a scoped remap of the app 's consistent utility palette. 52 + * The views use a small , fixed set of hardcoded utilities ( bg - white 53 + * cards , zinc borders , neutral text ) , so one place remaps them instead 54 + * of adding dark : variants to ~ 380 call sites . Unlayered head styles 55 + * beat crosswind 's layered utilities regardless of specificity. 56 + * / 57 + html . dark body { background - color : # 0 a0a0c ; color : # e4e4e7 ; } 58 + 59 + / * Surfaces * / 60 + . dark . bg - white { background - color : # 18181 b ; } 61 + . dark . bg - \ [ \ # f3f3f1 \ ] { background - color : # 0 a0a0c ; } 62 + . dark . bg - zinc - 50 , . dark . bg - zinc - 50 \ / 80 , . dark . bg - zinc - 50 \ / 48 { background - color : # 1 c1c1f ; } 63 + . dark . bg - zinc - 50 \ / 40 { background - color : rgba ( 255 , 255 , 255 , 0.02 ) ; } 64 + . dark . bg - zinc - 100 { background - color : # 26262 a ; } 65 + . dark . bg - blue - 50 { background - color : # 172554 ; } 66 + . dark . bg - emerald - 50 { background - color : # 052e2 b ; } 67 + . dark . bg - amber - 50 { background - color : # 3 a2a08 ; } 68 + . dark . bg - red - 50 { background - color : # 3 a1414 ; } 69 + 70 + / * Borders * / 71 + . dark . border - zinc - 200 , . dark . border - zinc - 200 \ / 80 , . dark . border - zinc - 100 { border - color : # 2 a2a2e ; } 72 + . dark . border - blue - 200 { border - color : # 1e3 a8a ; } 73 + . dark . border - emerald - 200 { border - color : # 0 f766e ; } 74 + . dark . border - amber - 200 { border - color : # 78500 a ; } 75 + . dark . border - red - 200 { border - color : # 7 f1d1d ; } 76 + 77 + / * Text * / 78 + . dark . text - neutral - 950 { color : # f4f4f5 ; } 79 + . dark . text - slate - 700 { color : # d4d4d8 ; } 80 + . dark . text - zinc - 600 , . dark . text - zinc - 500 { color : # a1a1aa ; } 81 + . dark . text - zinc - 700 , . dark . text - zinc - 800 { color : # d4d4d8 ; } 82 + . dark . text - blue - 700 , . dark . text - blue - 800 { color : # 93 c5fd ; } 83 + . dark . text - emerald - 700 { color : # 6e e7b7 ; } 84 + . dark . text - amber - 800 { color : # fcd34d ; } 85 + . dark . text - red - 700 { color : # fca5a5 ; } 86 + 87 + / * Hover states ( higher specificity than the base utilities above ) * / 88 + . dark . hover \ : bg - white : hover { background - color : # 26262 a ; } 89 + . dark . hover \ : bg - zinc - 50 : hover { background - color : # 26262 a ; } 90 + . dark . hover \ : bg - zinc - 100 : hover { background - color : # 2 f2f34 ; } 91 + 92 + / * Primary buttons invert to light - on - dark - text so they pop on dark surfaces * / 93 + . dark . bg - neutral - 950 { background - color : # f4f4f5 ; } 94 + . dark . bg - neutral - 950. text - white , 95 + . dark . bg - neutral - 950 . text - white , 96 + . dark . text - white . bg - neutral - 950 { color : # 0 a0a0c ; } 97 + . dark . hover \ : bg - neutral - 800 : hover { background - color : # d4d4d8 ; } 98 + / * Keep the small "P" brand mark dark - on - light * / 99 + . dark . bg - neutral - 950. rounded - xl > span , 100 + . dark [ aria - label = "Postline composer" ] . bg - neutral - 950 { color : # 0 a0a0c ; } 101 + 102 + / * Inputs + code * / 103 + . dark input , . dark textarea , . dark select { color : # f4f4f5 ; } 104 + . dark input : : placeholder , . dark textarea : : placeholder { color : # 71717 a ; } 105 + . dark code { background - color : # 26262 a ; color : # e4e4e7 ; } 106 + 107 + / * Shell surfaces ( targeted by data - attribute ; opacity / gradient variants ) * / 108 + . dark [ data - postline - content - shell ] , 109 + . dark [ data - postline - workspace ] , 110 + . dark [ data - postline - sidebar ] { background - color : # 0 a0a0c ; } 111 + . dark [ data - postline - workspace ] { 112 + border - color : # 2 a2a2e ; 113 + box - shadow : - 10 px 0 36 px rgba ( 0 , 0 , 0 , 0.4 ) ; 114 + } 115 + . dark [ data - postline - sidebar ] { background - color : rgba ( 24 , 24 , 27 , 0.5 ) ; } 116 + . dark [ data - postline - sidebar ] > . absolute { opacity : 0.35 ; } 117 + / * Sidebar nav : active item + white / xx controls and badges * / 118 + . dark . bg - \ [ \ # e8e8e6 \ ] \ / 90 { background - color : rgba ( 63 , 63 , 70 , 0.6 ) ; } 119 + . dark . bg - white \ / 95 { background - color : rgba ( 39 , 39 , 42 , 0.95 ) ; } 120 + . dark . bg - white \ / 72 { background - color : rgba ( 63 , 63 , 70 , 0.72 ) ; } 121 + . dark . bg - white \ / 60 { background - color : rgba ( 63 , 63 , 70 , 0.6 ) ; } 122 + . dark . hover \ : bg - white \ / 38 : hover , 123 + . dark . hover \ : bg - white \ / 60 : hover , 124 + . dark . hover \ : bg - white \ / 35 : hover { background - color : rgba ( 63 , 63 , 70 , 0.55 ) ; } 125 + . dark . bg - white \ / 48 { background - color : rgba ( 39 , 39 , 42 , 0.48 ) ; } 126 + 127 + / * Analytics chart — CSS overrides the hardcoded SVG palette ( CSS 128 + fill / stroke beat presentation attributes ) so the chart isn 't a 129 + light island on a dark page . * / 130 + . dark [ data - analytics - chart ] rect [ rx = "16" ] { fill : # 101014 ; } 131 + . dark [ data - analytics - chart ] line [ stroke = "#e4e4e7" ] { stroke : # 2 a2a2e ; } 132 + . dark [ data - analytics - chart ] text [ fill = "#18181b" ] { fill : # e4e4e7 ; } 133 + . dark [ data - analytics - chart ] rect [ fill = "#fff" ] { fill : # 26262 a ; stroke : # 3 f3f46 ; } 134 + . dark [ data - analytics - chart ] . bg - zinc - 100 { background - color : # 26262 a ; } 135 + 40 136 @ property - - postline - sidebar - width { 41 137 syntax : '<length>' ; 42 138 inherits : true ;