11html [data-theme = " light" ] {
22 --bg : #FBF9F4 ;
33 --surface : #FFFFFF ;
4- --surface-2 : #F3EFE6 ;
4+ --surface-2 : #f8f6f2 ;
55 --border : #E3DDCF ;
66 --border-soft : #EBE6DA ;
77 --text : #0B0B0B ;
@@ -17,6 +17,17 @@ html[data-theme="light"] {
1717 --teal-dim : rgba (163 , 60 , 75 , .12 );
1818 --nav-bg : rgba (251 , 249 , 244 , .86 );
1919 --on-accent : #FBF6F0 ;
20+
21+ /* OSS lifecycle states. The brand palette is deliberately one warm hue, so these are the
22+ only tokens that carry a second signal; they stay muted to sit beside the red. */
23+ --state-active : #2E7D64 ;
24+ --state-active-dim : rgba (46 , 125 , 100 , .12 );
25+ --state-maintenance : #96620A ;
26+ --state-maintenance-dim : rgba (150 , 98 , 10 , .12 );
27+ --state-security : #C71F38 ;
28+ --state-security-dim : rgba (199 , 31 , 56 , .12 );
29+ --state-archived : #6B665C ;
30+ --state-archived-dim : rgba (107 , 102 , 92 , .1 );
2031}
2132
2233html [data-theme = " dark" ] {
@@ -37,6 +48,16 @@ html[data-theme="dark"] {
3748 --amber-dim : rgba (218 , 53 , 80 , .16 );
3849 --teal-dim : rgba (232 , 99 , 122 , .16 );
3950 --nav-bg : rgba (11 , 11 , 11 , .86 );
51+
52+ /* Lifted for the dark surfaces; same four states as the light theme. */
53+ --state-active : #58B79A ;
54+ --state-active-dim : rgba (88 , 183 , 154 , .16 );
55+ --state-maintenance : #DCA23C ;
56+ --state-maintenance-dim : rgba (220 , 162 , 60 , .16 );
57+ --state-security : #E8637A ;
58+ --state-security-dim : rgba (232 , 99 , 122 , .16 );
59+ --state-archived : #8A847C ;
60+ --state-archived-dim : rgba (138 , 132 , 124 , .14 );
4061}
4162
4263html {
@@ -672,6 +693,136 @@ html[data-theme="light"] .theme-toggle {
672693 }
673694}
674695
696+ /* ============================================================
697+ Package lifecycle cards
698+ ============================================================ */
699+
700+ /* auto-fill keeps the packages grid responsive without breakpoints, since the
701+ number of packages changes with every cron run. */
702+ .packages-grid {
703+ display : grid ;
704+ grid-template-columns : repeat (auto-fill , minmax (240px , 1fr ));
705+ gap : 18px ;
706+ }
707+
708+ .package-card {
709+ border-top-width : 4px ;
710+ transition : box-shadow .2s ease , transform .2s ease ;
711+
712+ & :hover {
713+ box-shadow : 0 6px 20px var (--accent-dim );
714+ transform : translateY (-2px );
715+ }
716+
717+ .card-top {
718+ margin-bottom : 12px ;
719+ }
720+
721+ h3 {
722+ margin : 0 ;
723+ }
724+ }
725+
726+ /* The pill carries the state, so it is the loudest thing on the card after the name. */
727+ .package-state {
728+ display : inline-flex ;
729+ align-items : center ;
730+ gap : 7px ;
731+ margin-bottom : 8px ;
732+ padding : 4px 10px ;
733+ border : 1px solid var (--accent );
734+ border-radius : 999px ;
735+ background : var (--accent-dim );
736+ color : var (--accent );
737+ font-family : var (--mono );
738+ font-size : 10.5px ;
739+ font-weight : 600 ;
740+ letter-spacing : .1em ;
741+ text-transform : uppercase ;
742+
743+ /* Each state also changes the marker's shape, so the four are still telling apart
744+ when the hues are not (colour blindness, greyscale printing, forced-colours mode). */
745+ & ::before {
746+ content : ' ' ;
747+ flex : none ;
748+ width : 7px ;
749+ height : 7px ;
750+ border-radius : 50% ;
751+ background : var (--accent );
752+ }
753+ }
754+
755+ .package-card--active {
756+ --accent : var (--state-active );
757+ --accent-dim : var (--state-active-dim );
758+ }
759+
760+ /* Hollow marker: still supported, no longer moving. */
761+ .package-card--maintenance {
762+ --accent : var (--state-maintenance );
763+ --accent-dim : var (--state-maintenance-dim );
764+
765+ .package-state ::before {
766+ background : transparent ;
767+ box-shadow : inset 0 0 0 2px var (--accent );
768+ }
769+ }
770+
771+ /* Haloed marker reads as a warning without leaning on hue alone. */
772+ .package-card--security-only {
773+ --accent : var (--state-security );
774+ --accent-dim : var (--state-security-dim );
775+
776+ .package-state ::before {
777+ box-shadow : 0 0 0 3px var (--accent-dim );
778+ }
779+ }
780+
781+ /* Archived and unrecognised states recede: dashed edge, quieter surface, square marker. */
782+ .package-card--archived ,
783+ .package-card--unknown {
784+ --accent : var (--state-archived );
785+ --accent-dim : var (--state-archived-dim );
786+ border-style : dashed ;
787+ border-top-style : solid ;
788+
789+ h3 {
790+ color : var (--text-muted );
791+ }
792+
793+ .package-state ::before {
794+ border-radius : 2px ;
795+ background : transparent ;
796+ box-shadow : inset 0 0 0 2px var (--accent );
797+ }
798+
799+ .badges img {
800+ opacity : .65 ;
801+ }
802+ }
803+
804+ .package-archived {
805+ margin : 0 ;
806+ color : var (--text-dim );
807+ font-size : 12px ;
808+ }
809+
810+ .packages-generated-at {
811+ margin-top : 22px ;
812+ color : var (--text-dim );
813+ }
814+
815+ /* Respect a reduced-motion preference: the lift is decoration, the colour is the message. */
816+ @media (prefers-reduced-motion : reduce) {
817+ .package-card {
818+ transition : none ;
819+
820+ & :hover {
821+ transform : none ;
822+ }
823+ }
824+ }
825+
675826.standards-grid {
676827 display : grid ;
677828 grid-template-columns : repeat (3 , 1fr );
0 commit comments