@@ -6195,6 +6195,304 @@ select.input {
61956195 margin-left : 4px ;
61966196}
61976197
6198+ /* ResourceRow — unified expandable row anatomy used by the Manage page so
6199+ installed models and backends share the same visual grammar as the Install
6200+ gallery (icon, name, description, badges, expandable detail panel). */
6201+ .resource-row { transition : background var (--duration-fast ) var (--ease-default ); }
6202+ .resource-row .is-dimmed { opacity : 0.55 ; transition : opacity 0.2s ; }
6203+ .resource-row .is-expanded { background : var (--color-bg-tertiary ); }
6204+
6205+ .resource-row__chevron-cell { width : 30px ; }
6206+ .resource-row__icon-cell { width : 64px ; }
6207+
6208+ .resource-row__icon {
6209+ width : 48px ;
6210+ height : 48px ;
6211+ border-radius : var (--radius-md );
6212+ border : 1px solid var (--color-border-subtle );
6213+ background : var (--color-bg-primary );
6214+ display : flex;
6215+ align-items : center;
6216+ justify-content : center;
6217+ overflow : hidden;
6218+ flex-shrink : 0 ;
6219+ }
6220+ .resource-row__icon > img {
6221+ width : 100% ;
6222+ height : 100% ;
6223+ object-fit : cover;
6224+ }
6225+ .resource-row__icon > i {
6226+ font-size : 1.25rem ;
6227+ color : var (--color-accent );
6228+ }
6229+
6230+ .resource-row__detail-row > .resource-row__detail-cell {
6231+ padding : 0 ;
6232+ background : var (--color-bg-primary );
6233+ border-top : 1px solid var (--color-border-subtle );
6234+ }
6235+ .resource-row__detail {
6236+ padding : var (--spacing-md ) var (--spacing-lg );
6237+ }
6238+ .resource-row__detail h4 {
6239+ font-size : var (--text-xs );
6240+ font-weight : 600 ;
6241+ letter-spacing : 0.06em ;
6242+ text-transform : uppercase;
6243+ color : var (--color-text-muted );
6244+ margin : 0 0 var (--spacing-sm ) 0 ;
6245+ display : flex;
6246+ align-items : center;
6247+ gap : var (--spacing-xs );
6248+ }
6249+ .resource-row__detail h4 i { color : var (--color-accent ); }
6250+ .resource-row__detail-grid {
6251+ display : grid;
6252+ grid-template-columns : max-content 1fr ;
6253+ gap : 6px var (--spacing-md );
6254+ }
6255+ .resource-row__detail-grid dt {
6256+ color : var (--color-text-muted );
6257+ font-size : var (--text-xs );
6258+ text-transform : uppercase;
6259+ letter-spacing : 0.06em ;
6260+ align-self : start;
6261+ padding-top : 2px ;
6262+ }
6263+ .resource-row__detail-grid dd {
6264+ margin : 0 ;
6265+ font-size : var (--text-sm );
6266+ color : var (--color-text-primary );
6267+ min-width : 0 ;
6268+ word-break : break-word;
6269+ }
6270+ .resource-row__detail-md {
6271+ color : var (--color-text-secondary );
6272+ line-height : 1.6 ;
6273+ font-size : var (--text-sm );
6274+ }
6275+ .resource-row__detail-md p : first-child { margin-top : 0 ; }
6276+ .resource-row__detail-md p : last-child { margin-bottom : 0 ; }
6277+
6278+ /* Description line directly under the row name — Install gallery already
6279+ does this; Manage rows used to show only the bare name. */
6280+ .resource-row__desc {
6281+ display : block;
6282+ font-size : var (--text-xs );
6283+ color : var (--color-text-muted );
6284+ max-width : 42ch ;
6285+ overflow : hidden;
6286+ text-overflow : ellipsis;
6287+ white-space : nowrap;
6288+ margin-top : 2px ;
6289+ }
6290+
6291+ /* ResourceActions — split lifecycle vs destructive with a thin divider so
6292+ the trash icon doesn't sit at the same eye-weight as the routine buttons.
6293+ Used now only for the rare row whose actions can't collapse into the
6294+ kebab menu (e.g. a "Protected" badge on system backends). */
6295+ .resource-actions {
6296+ display : inline-flex;
6297+ align-items : center;
6298+ gap : var (--spacing-xs );
6299+ justify-content : flex-end;
6300+ }
6301+ .resource-actions__group {
6302+ display : inline-flex;
6303+ align-items : center;
6304+ gap : var (--spacing-xs );
6305+ }
6306+ .resource-actions__divider {
6307+ width : 1px ;
6308+ height : 20px ;
6309+ background : var (--color-border-subtle );
6310+ margin : 0 var (--spacing-xs );
6311+ flex-shrink : 0 ;
6312+ }
6313+
6314+ /* ActionMenu — kebab trigger + popover menu. Borrows claudemaster's
6315+ restrained pattern: button reads as a quiet ellipsis at rest, lights up
6316+ on row hover, and the menu items hold typography-first weight (icon +
6317+ label, no fills until hover). The trigger stays at low opacity until the
6318+ user reaches for the row, so dense tables don't read as control panels. */
6319+ .action-menu__trigger {
6320+ display : inline-flex;
6321+ align-items : center;
6322+ justify-content : center;
6323+ width : 28px ;
6324+ height : 28px ;
6325+ padding : 0 ;
6326+ border : 1px solid transparent;
6327+ border-radius : var (--radius-sm );
6328+ background : transparent;
6329+ color : var (--color-text-muted );
6330+ cursor : pointer;
6331+ font-size : var (--text-sm );
6332+ opacity : 0.45 ;
6333+ transition :
6334+ opacity var (--duration-fast ) var (--ease-default ),
6335+ color var (--duration-fast ) var (--ease-default ),
6336+ background var (--duration-fast ) var (--ease-default ),
6337+ border-color var (--duration-fast ) var (--ease-default );
6338+ }
6339+ .resource-row : hover .action-menu__trigger ,
6340+ .action-menu__trigger : focus-visible ,
6341+ .action-menu__trigger .is-open {
6342+ opacity : 1 ;
6343+ }
6344+ .action-menu__trigger : hover ,
6345+ .action-menu__trigger .is-open {
6346+ background : var (--color-bg-tertiary );
6347+ border-color : var (--color-border-subtle );
6348+ color : var (--color-text-primary );
6349+ }
6350+ .action-menu__trigger : focus-visible {
6351+ outline : 2px solid var (--color-border-focus );
6352+ outline-offset : 2px ;
6353+ }
6354+ .action-menu__trigger--compact {
6355+ width : 24px ;
6356+ height : 24px ;
6357+ font-size : var (--text-xs );
6358+ }
6359+
6360+ .action-menu {
6361+ display : flex;
6362+ flex-direction : column;
6363+ min-width : 200px ;
6364+ padding : 4px ;
6365+ outline : none;
6366+ }
6367+ .action-menu__item {
6368+ display : flex;
6369+ align-items : center;
6370+ gap : var (--spacing-sm );
6371+ padding : 8px 10px ;
6372+ border : 0 ;
6373+ border-radius : var (--radius-sm );
6374+ background : transparent;
6375+ color : var (--color-text-primary );
6376+ font-family : inherit;
6377+ font-size : var (--text-sm );
6378+ font-weight : 500 ;
6379+ text-align : left;
6380+ cursor : pointer;
6381+ width : 100% ;
6382+ transition : background var (--duration-fast ) var (--ease-default ),
6383+ color var (--duration-fast ) var (--ease-default );
6384+ }
6385+ .action-menu__item .is-active ,
6386+ .action-menu__item : hover : not (: disabled ) {
6387+ background : var (--color-bg-tertiary );
6388+ }
6389+ .action-menu__item : disabled {
6390+ cursor : not-allowed;
6391+ opacity : 0.45 ;
6392+ }
6393+ .action-menu__icon {
6394+ width : 14px ;
6395+ text-align : center;
6396+ color : var (--color-text-muted );
6397+ font-size : var (--text-xs );
6398+ flex-shrink : 0 ;
6399+ }
6400+ .action-menu__item .is-active .action-menu__icon ,
6401+ .action-menu__item : hover : not (: disabled ) .action-menu__icon {
6402+ color : var (--color-text-primary );
6403+ }
6404+ .action-menu__label {
6405+ flex : 1 ;
6406+ min-width : 0 ;
6407+ white-space : nowrap;
6408+ overflow : hidden;
6409+ text-overflow : ellipsis;
6410+ }
6411+ .action-menu__shortcut {
6412+ font-family : var (--font-mono );
6413+ font-size : 10px ;
6414+ color : var (--color-text-muted );
6415+ letter-spacing : 0.04em ;
6416+ flex-shrink : 0 ;
6417+ }
6418+ .action-menu__item .is-danger { color : var (--color-error ); }
6419+ .action-menu__item .is-danger .action-menu__icon { color : var (--color-error ); }
6420+ .action-menu__item .is-danger : hover : not (: disabled ),
6421+ .action-menu__item .is-danger .is-active {
6422+ background : var (--color-error-light );
6423+ color : var (--color-error );
6424+ }
6425+ .action-menu__item .is-danger : hover : not (: disabled ) .action-menu__icon ,
6426+ .action-menu__item .is-danger .is-active .action-menu__icon {
6427+ color : var (--color-error );
6428+ }
6429+ .action-menu__divider {
6430+ height : 1px ;
6431+ background : var (--color-border-subtle );
6432+ margin : 4px 2px ;
6433+ }
6434+ .action-menu__badge {
6435+ display : flex;
6436+ align-items : center;
6437+ gap : var (--spacing-sm );
6438+ padding : 8px 10px ;
6439+ font-size : var (--text-xs );
6440+ font-weight : 500 ;
6441+ letter-spacing : 0.06em ;
6442+ text-transform : uppercase;
6443+ color : var (--color-text-muted );
6444+ }
6445+ .action-menu__badge > i { color : var (--color-text-muted ); font-size : var (--text-xs ); width : 14px ; text-align : center; }
6446+
6447+ /* Pulse modifier — subtle ring on the Pin button when a model is pinned, so
6448+ pinning is visible at a glance without a second icon next to the name. */
6449+ .btn--pulse {
6450+ animation : btnPulseWarning 1.6s ease-in-out infinite;
6451+ }
6452+ @keyframes btnPulseWarning {
6453+ 0% , 100% { box-shadow : 0 0 0 0 rgba (235 , 203 , 139 , 0 ); }
6454+ 50% { box-shadow : 0 0 0 4px rgba (235 , 203 , 139 , 0.18 ); }
6455+ }
6456+
6457+ /* StatCard clickable variant — the Manage summary cards double as shortcuts
6458+ to the relevant tab + filter, so the card needs a real button affordance. */
6459+ .stat-card [data-clickable = "true" ] {
6460+ cursor : pointer;
6461+ user-select : none;
6462+ }
6463+ .stat-card [data-clickable = "true" ]: hover {
6464+ border-color : var (--stat-accent , var (--color-border ));
6465+ transform : translateY (-1px );
6466+ }
6467+ .stat-card [data-clickable = "true" ]: focus-visible {
6468+ outline : 2px solid var (--color-border-focus );
6469+ outline-offset : 2px ;
6470+ }
6471+
6472+ /* Manage summary marker — same .stat-grid layout. Top margin separates the
6473+ cards from the System Resources card above (otherwise they sit too close
6474+ to the RAM bar) and bottom margin tightens the gap to the tabs below. */
6475+ .manage-summary {
6476+ margin-top : var (--spacing-xl );
6477+ margin-bottom : var (--spacing-lg );
6478+ }
6479+
6480+ /* Screen-reader-only label, used for table headers whose visual cell needs
6481+ no label (kebab-only Actions column, toggle-only Enabled column). The
6482+ header still announces correctly to assistive tech without making the
6483+ table feel like it's labelling sparse columns twice. */
6484+ .visually-hidden {
6485+ position : absolute;
6486+ width : 1px ;
6487+ height : 1px ;
6488+ padding : 0 ;
6489+ margin : -1px ;
6490+ overflow : hidden;
6491+ clip : rect (0 , 0 , 0 , 0 );
6492+ white-space : nowrap;
6493+ border : 0 ;
6494+ }
6495+
61986496/* Reduced motion accessibility */
61996497@media (prefers-reduced-motion : reduce) {
62006498 * , * ::before , * ::after {
0 commit comments