"""Source-color analysis only; no application rendering or screenshot modification. Run: python .local/palette-contrast-20260912.py WCAG sRGB definition: https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html Float source constants are retained. Hex labels are rounded display conveniences. """ import json def rgb(h): return tuple(int(h[i:i+2], 16)/255 for i in (0, 2, 4)) def linear(c): return c/12.92 if c <= .04045 else ((c+.055)/1.055)**2.4 def encoded(c): return 12.92*c if c <= .0031308 else 1.055*c**(1/2.4)-.055 def lum(c): return sum(w*linear(v) for w, v in zip((.2126, .7152, .0722), c)) def contrast(a, b): x, y = sorted((lum(a), lum(b))) return (y+.05)/(x+.05) def hexcode(c): return '#' + ''.join(f'{round(v*255):02X}' for v in c) C = dict(white=(1,1,1), BG=(.945,.956,.969), INK=(.13,.18,.25), MUTED=(.43,.48,.55), TEAL=(0,.48,.43), LINE=(.86,.89,.91), amber=(.72,.47,.10), entity=(.16,.4,.71), actor=(.58,.35,.7), scenario=(.65,.33,.4), state=(.38,.39,.68), other=(.25,.48,.56)) for name, h in dict(canvas='F6F8FB', activation='F3F8F8', region='F7FAFD', machine='EAF1F8', navfill='DAEEEB', navborder='97CBC3', rowfill='E0F7F2', edge='909EAD', trace='866BA8', keyword='763EA0', identifier='145D8B', string='18714F', number='A34E1E', comment='6F7984', error='BA263E', punctuation='5B6575', diagnostic_error='AE2E40', diagnostic_warning='915D17').items(): C[name] = rgb(h) # iced_core 0.14 palette::Primary::generate and mix use linear-light blending. C['editor_selection'] = tuple(encoded(.6*linear(a)+.4*linear(b)) for a,b in zip(C['TEAL'], C['BG'])) pairs = [('INK','white'), ('MUTED','white'), ('MUTED','BG'), ('MUTED','machine'), ('TEAL','white'), ('TEAL','rowfill'), ('LINE','white'), ('LINE','activation'), ('edge','canvas'), ('navfill','white'), ('navborder','navfill'), ('navborder','white'), ('activation','white'), ('region','machine')] for name in ('entity','actor','TEAL','amber','scenario','state','other'): C[name+'_tint'] = tuple(.94+.06*v for v in C[name]) pairs.append((name,name+'_tint')) for name in ('keyword','identifier','string','number','comment','error','punctuation'): pairs += [(name,'BG'), (name,'editor_selection')] for name in ('diagnostic_error','diagnostic_warning'): pairs.append((name,'BG')) # Candidate A retains category accents. Candidate B uses neutral content and blue selection. for name,h in dict(A_ink='202C3A', A_secondary='4B5968', A_boundary='667586', A_accent='00665C', A_selection='D9EEE8', A_amber='865B00', A_actor='754499', A_other='326B80', B_ink='202020', B_secondary='494949', B_boundary='595959', B_accent='124E96', B_selection='E2ECFA').items(): C[name]=rgb(h) for prefix in ('A','B'): pairs += [(prefix+'_ink','white'), (prefix+'_secondary','BG'), (prefix+'_boundary','white'), (prefix+'_boundary','machine'), (prefix+'_accent','white'), (prefix+'_accent',prefix+'_selection'), (prefix+'_ink',prefix+'_selection')] pairs += [('A_amber','white'), ('A_amber','BG')] for name in ('A_actor','A_other','A_amber'): C[name+'_tint']=tuple(.94+.06*v for v in C[name]) pairs.append((name,name+'_tint')) for name in ('keyword','identifier','string','number','A_secondary','error','punctuation'): pairs.append((name,'A_selection')) result=[] for a,b in pairs: ratio=contrast(C[a],C[b]) result.append(dict(foreground=a, background=b, fg_hex=hexcode(C[a]), bg_hex=hexcode(C[b]), ratio=round(ratio,6), normal_text_4_5=ratio>=4.5, meaningful_graphic_3=ratio>=3)) print(json.dumps(result,indent=2))