From a57be0941dbfc6b42abe774cece97d1401cc17df Mon Sep 17 00:00:00 2001 From: Sean Perkins <13732623+sean-perkins@users.noreply.github.com> Date: Wed, 10 Apr 2024 16:00:03 -0400 Subject: [PATCH] feat(css): global link classes for standalone and underline (#29298) Issue number: Internal --------- ## What is the current behavior? N/A ## What is the new behavior? - Adds two global classes for `.ionic-link` (standalone) and `.ionic-link-underline` (underline) appearances. - The global classes apply when directly applied to an anchor element (`a`) or when used on a parent container that renders a link internally. **Usage** Developers will need to import the link global stylesheet at this time to leverage the following CSS classes. ```html Standalone Underline
``` **Focus and Activated States** Developers should apply the `ion-focusable` and `ion-activatable` classes to the anchor elements to enable proper styling on a mobile device. For web-only usages, the fallback `:focus` and `:active` pseudo states will apply correctly. ```html Standalone Underline ``` ### Design Changes This section is areas of the implementation that are not consistent with the design and why. 1. Font size: Link font sizing is inherited from its content. This is to provide visual consistency when using a link within a paragraph or existing text content. Links should not have an explicit font size, but can be customized by the developer if a specific font size is desired. 2. Color: `currentColor` was used in place of `$ionic-color-neutral-900`. This is to provide better visual consistency when a link is used within content. Text color should be set on the body or text content, which would apply neutral-900 in places where it is applied. 3. The text underline offset in the designs is ~3px, but all of the design implementation is on a 4px grid. We've landed on 2px for the offset here. Discussed with Design and these proposed changes were verbally approved. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information --- core/src/css/link.ionic.scss | 120 ++++++++++++++++++ core/src/css/test/link/basic/index.html | 77 +++++++++++ core/src/css/test/link/basic/link.e2e.ts | 41 ++++++ ...ionic-md-ltr-light-Mobile-Chrome-linux.png | Bin 0 -> 8783 bytes ...onic-md-ltr-light-Mobile-Firefox-linux.png | Bin 0 -> 10266 bytes ...ionic-md-ltr-light-Mobile-Safari-linux.png | Bin 0 -> 8454 bytes ...ionic-md-ltr-light-Mobile-Chrome-linux.png | Bin 0 -> 5997 bytes ...onic-md-ltr-light-Mobile-Firefox-linux.png | Bin 0 -> 6794 bytes ...ionic-md-ltr-light-Mobile-Safari-linux.png | Bin 0 -> 5835 bytes ...ionic-md-ltr-light-Mobile-Chrome-linux.png | Bin 0 -> 9956 bytes ...onic-md-ltr-light-Mobile-Firefox-linux.png | Bin 0 -> 11970 bytes ...ionic-md-ltr-light-Mobile-Safari-linux.png | Bin 0 -> 9498 bytes ...ionic-md-ltr-light-Mobile-Chrome-linux.png | Bin 0 -> 4876 bytes ...onic-md-ltr-light-Mobile-Firefox-linux.png | Bin 0 -> 6025 bytes ...ionic-md-ltr-light-Mobile-Safari-linux.png | Bin 0 -> 4675 bytes 15 files changed, 238 insertions(+) create mode 100644 core/src/css/link.ionic.scss create mode 100644 core/src/css/test/link/basic/index.html create mode 100644 core/src/css/test/link/basic/link.e2e.ts create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-standalone-ionic-md-ltr-light-Mobile-Chrome-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-standalone-ionic-md-ltr-light-Mobile-Firefox-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-standalone-ionic-md-ltr-light-Mobile-Safari-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-standalone-nested-ionic-md-ltr-light-Mobile-Chrome-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-standalone-nested-ionic-md-ltr-light-Mobile-Firefox-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-standalone-nested-ionic-md-ltr-light-Mobile-Safari-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-underline-ionic-md-ltr-light-Mobile-Chrome-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-underline-ionic-md-ltr-light-Mobile-Firefox-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-underline-ionic-md-ltr-light-Mobile-Safari-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-underline-nested-ionic-md-ltr-light-Mobile-Chrome-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-underline-nested-ionic-md-ltr-light-Mobile-Firefox-linux.png create mode 100644 core/src/css/test/link/basic/link.e2e.ts-snapshots/link-underline-nested-ionic-md-ltr-light-Mobile-Safari-linux.png diff --git a/core/src/css/link.ionic.scss b/core/src/css/link.ionic.scss new file mode 100644 index 0000000000..9fc1f2828a --- /dev/null +++ b/core/src/css/link.ionic.scss @@ -0,0 +1,120 @@ +@use "../foundations/ionic.vars" as tokens; + +// Link: Shared Styles (Standalone & Underline) +// ------------------------------------------------------------------------------- +@mixin link-shared { + display: inline-flex; + + align-items: center; + + gap: 4px; + + transition: color 0.2s ease-in-out; + + font-weight: 400; + + text-decoration-color: inherit; + + text-underline-offset: 2px; + + cursor: pointer; + + // Link: Visited + // ------------------------------------------------------------------------------- + + &:visited { + color: tokens.$ionic-color-info-500; + } +} + +// Link: Standalone +// ------------------------------------------------------------------------------- + +@mixin ionic-link { + @include link-shared; + + // Link: Standalone - Hover + // ------------------------------------------------------------------------------- + + @media (any-hover: hover) { + &:hover { + text-decoration: underline; + } + } + + color: tokens.$ionic-color-info-400; + + text-decoration: none; + + // Link: Standalone - Focus + // ------------------------------------------------------------------------------- + + &:focus, + &.ion-focused { + outline: 2px solid tokens.$ionic-color-primary-100; + outline-offset: 2px; + + text-decoration: underline; + } + + // Link: Standalone - Active + // ------------------------------------------------------------------------------- + + &:active, + &.ion-activated { + color: tokens.$ionic-color-info-500; + + text-decoration: underline; + } +} + +a.ionic-link, +:not(a).ionic-link a { + @include ionic-link; +} + +// Link: Underline +// ------------------------------------------------------------------------------- + +@mixin ionic-link-underline { + @include link-shared; + + // Link: Underline - Hover + // ------------------------------------------------------------------------------- + + @media (any-hover: hover) { + &:hover { + color: tokens.$ionic-color-info-400; + } + } + + color: currentColor; + + text-decoration: underline; + + // Link: Underline - Focus + // ------------------------------------------------------------------------------- + + &:focus, + &.ion-focused { + outline: 2px solid tokens.$ionic-color-primary-100; + outline-offset: 2px; + + color: currentColor; + + text-decoration: none; + } + + // Link: Underline - Active + // ------------------------------------------------------------------------------- + + &:active, + &.ion-activated { + color: tokens.$ionic-color-info-500; + } +} + +a.ionic-link-underline, +:not(a).ionic-link-underline a { + @include ionic-link-underline; +} diff --git a/core/src/css/test/link/basic/index.html b/core/src/css/test/link/basic/index.html new file mode 100644 index 0000000000..2b921855bd --- /dev/null +++ b/core/src/css/test/link/basic/index.html @@ -0,0 +1,77 @@ + + + + +Lorem ipsum dolor sit amet consectetur, default link adipisicing elit.
+Lorem ipsum dolor sit amet consectetur, underline link adipisicing elit.
+Vbij_w#!l<*j!g3894?C0$QJ!zWJF@(?c7u9 z8bWw=l3kv}%Sb59>Pkj-G2`>P>+{1-icWXiqKpcHP$|@SaKIjw**d1wpr6Y#D)F7Z z4@wT^Bn#B;^&3v+5%|$CZzk9#%xuaD=Vk1{MrR^Gmd1%Bj>g;X0%fyH3VOHDSVQ>X zrx%?p^1Pwbut+lpy?E>4O5xopCGJO)5SO^H8DGh@dL?d8E4>+YQnP926lyJqBPuL@ z57!Q<6e2WoRvTRBOe!x`xwhfncCho#^}L)*FOZ)RjkW7hVULs#F!Wzq8qng+S^Q%u z<$WEM4xdKIRU58+{kU2`g+D;&$Cb~EBE`1Ls_>FhJc(Vgv!dsGZ=NZU`$yZoK btNix*H*4^K zTXN^CnB!Kvz7LwdP1e~`AGB6}CXn4F@2mlhDhBXtQBlI>=^aYBD(0^Al|xQ#qxrox zpqKPb1k4 se7f3F_%72!oi$tQuMt)_M{2(y%)N{+o+A52H5$#1a{7DNGtDL~z}}o` zHeFICsJU_a`olZ++U+rKXdE_ri=aRx(JL<7r>lOhqoF6ERzSxKU}E8)_4gDg`bO4q tIw0NN3jZ__!*u?t*gsnK-;MXQOMfcTnV>q(z#AeU`8O)k<&q{J{td$33%~#X literal 0 HcmV?d00001 diff --git a/core/src/css/test/link/basic/link.e2e.ts-snapshots/link-standalone-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/css/test/link/basic/link.e2e.ts-snapshots/link-standalone-ionic-md-ltr-light-Mobile-Firefox-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..c61fbc8373614316070563155269c07fe492e2d1 GIT binary patch literal 10266 zcmc(lbyQnTpzX0Dh2mN~xEFU15Zt9upad&UDeh2;ySo%E?i6>|26rp&?(o9*?vuOj z{pZSCZ>_A%$;z2IbLJ$o=ePHSs3^(2d;9(^3=GUWSrAYS1_sswdR&Q&2z?(F&LV|@ zp@5MEifgzU9AzN6YV;EHD!a2G2e7u@tc1P6s>}xb1W1WlgmQ_$(7y%v>tF&^fU1@L zxNpR }D7f_B$qb}N~U9@`?0vPp C$B)er{1ae;vDS{5=;iy%RQTU|t z60#MS(!(u|yf8NolB2hhKn?Uqf#O%K(Ux%6`W)asCHUgit lsCyaURo=z0xw!i&K|SUlFZAGGy#4d!2!- zsmokwt^3nfdu;aO7HTY>hskgDX4d!YazNLEMlKe0?_V*zeO%m&7%cd`gC`LwlCx~b z1*VNdAk__Fmnhhn^P`;jET;R}tDYBK_wMs2%G )I>u4HtFu z1miEn^ykG&7YQ(K!D7P7E7|}2TCfIqW5^!O0YgYl;7{M|5ZszRgTG*Js6nvq{6Er{ zNx4_dVcWDvNzTfV>0Cw|7OZVKN0ie+!l=~F@?5v&z9g(kgPfOd({yaQ2^rfeu@4)1 z%kO}m8 IlmA`Rm;Y=3wt%gZt~I^IS`X`G3*7xSKra+WUX|{5X;mp z1z&c!8>pl_TRHH#{Vm1{BfpX%@*%)Ia~|OsVj;h#gT aLzVI}$VEc@MTF!@hhrOy$2kc50#~*&EvX4V zFEx&mg|vNmt`W~-xRX+N&;O>=sE69V1o>|XsQ(>CV0(}oqtQ;pm!=Qs#655phGY6T zd-?>EKx%!=1d~{1-qR+cye(Z+TvPUugTDurAf^L}kAzl05IJTH`W+YIa=ztew?}!z zS$7WZrJmPO_CzMAg!dC=+USTrA`oOM7fwkUQtigYxE{zdo{I705GSjiXE$v#c0=js zFTa);cIl3_hfV}&-TnM_iL-4!D0F}UwbMXe;m5X>p6=IQ6slUGxha=XL27^0t9OLK zE>n2T-8SyE+iZ(gSWob(b-^Xe3ipB`+M1p%(?i7iJ*kcI)*(qfCvDVeXi`mU-pGXf zD7z^gHh6n@GU|Wr* N`%}iF@{G5fGCGR%nipDWeAcwdwM1Nd$i^cBc zpK5HZD6S?}HYVnV^AhX~cslS_!|ZG=gnbk{&gQHD`X*-K+g8f9X&0T8oO>;$92Jy) zT~cfHp|x8^iKp~9sh-4PZFR!z&Bo5e-G6AR=pYYlX%irH6it*&fi?BA8V$WqcqQNq zPFVZVfxn8ex`r`GM$8zcb2xhfhP^*CO*U3dgKNcO9|BRqSi4)XDYCQa Vh*o=CfrKewMtNs{s(X*DXa|xMpQs1w;5BX`h1D7 z^1{M#rT2#YwJm&LxnkE)|5LBrK(9KTR*foPSsI-&;g;wx`H~7!VAeo4^H7@(8&R{N zbYi)8MfHXfp71HyOZgY=*BI}?)c#Uyg6YGM%jEXB)33>}cA!E1I|}U)d^`7M*Q0#~ z`Qgdr;w8Hk5%`rjjxNY^xej%{&u~w_7E)q8jVpc(Svxxsc_59Ih=)3sD;^v1>r_q; zhaPqrO9e(-w8)8#kPiDjKO?)Nl{Y;R#jJ>Fq&PXW5`U7uXm(O{YHsNcHo>tQ?W(j* z8zZcPG#u?r=Jkw8AuQ^1*cg@}9J>R`TFzpKv8!(F88x<_(oLTCQHBlkdhFyYV9IJw zi%mAan|#;BNn!lhgqm4;>^J$9w#X-M&mG_;{cIC$E5FIT`ouYp>@ob?`gMwdjwTM? zYZs$CjwshuXuUinHk)Jr(I1sOH;mUWd?Qg*@|;@u&>|3^!Uokhr2jsB)9nxIo_KA} z7clDaS|B(o_yWo{dyT%l_D(EjTllqr6QC7~nK|3|!1bzu*`N!uf3%krCmVF&`jzng z>ka%TyZb7Z6&M>6y}(1Cx~k=0) -iDc0IPQCh; zOFh+GKdGQJzxiVTE{ 7c(W~B3zt7k??l1Bf z+LqN|VO9&@qrcn6Z-KO-{fvWDx{jNY_~a6O(yxZ-(w*>nPk%k+PxHlwCEJ}XrS4nS zM*k)`zMgORJPf%TI8apO8Nd-S<~7>hOkginw3zboq1#V9@9r{~=6o1iaK+C}B=7E( zWx@J;6gZ6XYvIvH5HtVE4M4?tbK~%>3-T2io5HV4jA9k&e!7uMZ`dP`(?((EQYEQG zG4>hw_txyx{@Wk`;vq%97%KdyZbn~css! 5lnLgeRHsH+VvNiq* {#V&g)bMWjUf4; z6{C)$b=DZfT{;HuhA^c6S;~)Uwy{h |D|dCjt2 zZ-yhE9sh~o@Zq&twrFX-rY={q&9}j>cb0J|W(Wf@k++@yJ<_=VliEBcn^1*DVe~#0 zmgFSqFlPm2_OJEIRBE^BPmS>@=>OgXxU&g_g9Z<$5&QmGo$_N1XvajRLEa`-TpJZ` z{JG54pQGqnHVDw0Cv6_<=^kEwql#jY`WgSsse!m+OLsWzY3tN>MST`Hd;U-oVnNSu zgxVKudLC&~QOs}v?z~3*{h{iOC-tx<%jYH9mZkFW#C6@&AxC8?ViipuRNlSBI8e#K zlxJ!@YKQr9$y$(p(!@=3x2_o}y;e}MGfF$fG!s?1W>R{D;-3JoudAu9KMktVX96qY zUMD8oMo gi3S!duR--8ya zP|Yc(MtxZuQPIr$Wb5riJ7IIT&q^*MVm %}cj!)eY+-x9xb$j_-Z>5(Rm>`xmrt?cN K z*kuZGtvL!#rD~z7pw5jI>Nt-jdA|Dc8DCER!TrH)^qh~1sG@jN3&~Tv=Y5rT^!8$9 zSaRh(AA0+Yh9Gi_#|Dp(Rs+46kXd 2<=X%D={Ok$rqZ#Vw^9rLCGvWuH2E;TO^%P zCK+3CM3>CBw%h7h*j2k=l>v`K%wvTVF0NB?bQ|^O*GhvNu##d`yySEWde5TfFmJ|I z!U}tycbD@JltKxFj~hTo9piu@My9C5{b<bY(FIIeBg`S-D-M5i0xhC0kiAT-h74`ZZJ}*{pP3J3LsY*- r5GM7j2lOau{33tWzgX?=hvM1ADQU7?3D8~8#9Y3?v&(^5_a_(CIQd6 z+CcDC4pS;YIXY3HkcOW!^R}b*xf67zP=FE|m)k$Ahq6Qlhr74fopB=fDs$*q1FCuY z($5DIVu$g9aC_wSqswm&6`^=VkMfru@+0;w9rOcK4k@8>I4JP}?NtsdWuW5u;Q#+a zJm-P;C5p79LBkWaz-+^VmX{Yw*+eM&W&nvk>97nZk9c6XRPa z45w03WNiBRe={!^daqe81tb6Rv1<%Gyej2D)m%D$bR1GBPhRf82%+ayHrxHo*$7Dn z;K*cxBoe_92xUkwC<%w8#j%&QVn}%ElcXAWhd72oYzZ}1ne@ nk94g>T#rW z8|1q?KoqOUP#C_z)`y-p{ysC=sa@GX0`kO-Yq89R1y2oIh+`iLs)$sO+@U#}o8`rH z3T*_BW#Xdgr3E`F-x>EbQ3uEnsXnptDhe&evlrIX1D 4l()Z9}Z z`I-8C_j|X^44#z~)bq6s*Q1k?<_9Yu=}(%*)ZooME}L*AJd<#A5qhI5#m&O*U&*+s z0aTC%T`X+{n-iuJCzj>aZ-c?&KGfh@DXL?1``(h#7Iqcyg5~wgaabg3*k$a03#>nb zRX@oI01T1+gLZT3Kqq+YmJePeO esTD2P=zQpHORHD|>EonqfRQe`k3AeLbReLba6e>Owh4y;5K3{=RoPI{K}~ zGXT-A>zJEJvW@}!Am+>K10<(Il!hCli>?4XxhVV8GFgqGC6OyiHJG9xCw2FyI{f~E zwU@vA_{Tw&xfr2&J&Nv0imygljr7fXpbpEZKG5LFd@&v*syYf!zO z?7Qwmv)*yxR}>S&FGG``yRpMgs4|X9zOwoKrh)jhuaBA}X*4enxyEvFjOdT2Dv5Kj zFAw8-VlL>U-CAO~!nkT5 9H$0InIF!8szcghg&oY!?mduuGFQ2uV>_DxU zHTHRGrM}e4T$h>9*v$6geLOr#7_w&?aSlTq9#fMR%TIN(B#E=bx6J^tP)3KLJWc#h zQq^k^h)=0!+^)`w@bFSsu0j#Zd{bzNUILofIhkY+V8L5Nu_nU3Las;TF0e`-T+QVU zaepFYXT=^6g=_efH~YHK(FwT(+=a3^m(56Iy%URzb%uO#V^IYv-z_8-v>2J@&+*Ve zEa3?$+v=T4D7{_T$q8!jSe1Gpc L`M5z4mm*fX;u<7H90 z7%eZ&-eJA8*c^^sohr9uf*h?jXZ qRZy>Ko4Q-zWBVTt{{9gu6Gj zpcB{KjriICb+$HKgJzyKiDFE5FASPa9KFa_0q1M
RA1B(TI-m1 zolU|tDUJaqLyT5Oj6q3q8VN6+tp%0|L0qR@f9q#O`D#CvScjK^lfqY`i%d8B4bi$N z=k2E&LgyW#7d}v1>1S7a#OFg~IQD`|q-`#$xk4Sw?NAKF;NE0HeE^H$Zsz?1pEx_? zKMnPCW-cSP#(Z-8bTQBLBfi>OFl=Bk3Pv-bxu587Pcn(WKRb mQ{HMN^EI3$UUB^`58vv$;M9HZ%=^2}~SK&0&wG{8h_hbd#MJvfsmQY^x zxDr)*q>3tAu2y3FeNDpJuYGin%-XtTqo
MgEJ 0 z0Vao{vJ0M5>qW&2Dj#c#t*dJ99@IW~d2nbHl N;3@8=m}TJ56pb8Q)~H#Tz4B_X_Jg$)8WttnO51IK)tbL~qx%|G%%QToK!sSvaZ z8#cfY-Qk1`U3#!i=AtMUB0yx2tYTF2oSMYY!VuEMC}d)syFBcJJ)w9$X5K-PiC{|w z^`~tDPD&dJK!Rb^{gkjzSWrl}Q* 2Fa?Fb8NM)RM339qMdysBivM`i6=UYMA?3zq$|%uhjeB z zeu@+Mcs@DSEq&^1gAT}#0AF?By^aP4?ekacNwRYKjh%H&0rRlSwDznHL7&W?Unrxh zv;&;-Xy16Vy0d#_s=R=bTnsx=H?vvNSmZ8fUsNGEIyMjEiw k zm^LE!mPCYOPdFv4y_U}o^&s-L
|4Tpf?pF}ja3tlU1YB{@EqG>AbD}^k8$a=1IS^pE*|+Ec znXU4<7|vbelkZ;I97oT8r$>jz+SztOm-d@wNW)eHb+@j(Lx>(mP%K;+hf>4`wT&f0 zB6v0zZO38*gcDIU6dJgZ)wiV&1jOW_MLo46ygv1+$oSXA qJd>}8!A)d z@N9J~5$qh~^38zRcLtsa?WDiqeAswf=BjZMq4eHeT`PEAyVeqn@D|q36KAgz%ofkK z@#E`Ff@E|<^Bg4|ruheegD0o!??w}>y;gIa3FmDx$1*1Z{HtPEf~1z1ELNVrxmCbd zUFIk?KeOS@i-`-@vmGkFM_n8ZrsFt8NA-w36>sMh3bqz+AAWjD(g!PQM!c)OJ~SU_ zB7h;=_dIzl52ZE)p5cQn;9 T8Zb>xoN%G3mUhmrg5OWs#P~g=DgL?*!|N*y z@pD*TfYO%g8LM5$5y^9Suyj@d&93Z@&7d0|%F@|C4n3JJ#t|cu1*T@-oQ*eMS3i&R zD0W*4p!M=j_Y1! e&%QM%O}8oTRVIS;*9uCs#L9&MuFgF7N<(pukcx(i+Xbxp^GC* z>(KCNW;`~RZ`SbM;T-~Zf%XbK1;W)>3@>-Xg~jW4+cdSa(}=2W=gv!d+{pm1exE5m zaqIzNKTo{9-wb73G3qRb8bYbwwW!3v--}`POwE#}X>t=ku_2Wnj#Rj3bw0@EjWZm* z&j5!D;Nf8%de-r@ciD h7Z=!u8ZCvFDfU_w5xq`196gejF=In z{jijK>+KY2ak7;ApRur5tTfdibY5+PIjayr9@J^$G-PDOqaKp0nvHMG@m#I3tLvyh z`pH$YIh8i5x=_5)t>vicG^7VMe8l&DQ#EMu+c4n%Nrv&KEraM0ivzYr!d`R4J;8a< zGCrl&@P=>__b{D>ZW^-}6a%+%``lv1R*;vpVhktpnbHEYazfU1O>dYX>Pg3vOu` z<)L+|YL-7m6B(mSAK0uC{oOGR%$S-IXBB={>nZnuFGE2jiSLg$?YO?p9iNgnpeXaA ziTenedcBi-Soat#&Ppm3_y}A82YrYe+XP&2VABH;Y)e3TWM(L$S;4g6AD0R6we!m* zOI*(~e~l7qHk42JiKE7wv`4itY*-+x*6qH(4wQ_CnciVW8;zC WpkpQ z$y)_U8Sv4sX`oRIx*%Q i8DQ7!+%V!=Z<$c%H)6;4nMZ$`HY!=fI4 zB~Q~7SD21L+PQyL;&&k@WVh!deBR4s 94CWT${UWg;)18@ z3H0@VRxL&jfg!)YK!&{o`Ym^sA*9cXgM4KY`RWk>U5kujmAk)LHNjX9)EWVL+;wh; zB5@SNGI&*1EoX!6=BGb|2)p+qTgtgAsQd)8e7gayCMTxNT=6hcbotA*AU&XU+7#hQ zT>p5&N&0Mo&>^;6;D*RqVv_8SK${voeVWSRL#3x*`+0g{pGykqH1R?$>z_0OA1@n_ z>KLO9A|yXF1i4+PO_NrXh4(lU_4jux;vDX&+1a?kscEL5VMlr9yRH^THbEV(Ip$f7 z7>Jk|#7*DEKnBi*2dee=W6~Y-uhxUFH&o`Ynt8&*UyTE((XROa*l7O`<=+2QMa~9! z+ zY1RM;5MwekDIo=yjtXzNKT9y#wa~m&L7x>a+CO5f!2M4pLCw6VVZ^)5bzJH~(~Pf` zNvMIm*AQ 1fO<}|ke zEcF;7r<$Rm6dDTNcWE?_C_x`}EU({i_I^4mBb`W34>pHS1?HC_4GodOg0!Rr^9o zmX?JgHViRaT%XiO4F8lBz{K`u)6i`hdlE`dl|bva@=Tj2{*&MRIXL$cq8^MNp>$h| zQ+QN8S0fk;q%eG-LlGsD6Zh9a9hGY|c1Ox$b{@b8Qe!u@;y@4URqtEHlYH-LWTMWd z)8=yd$PJqm2RQ?BV<;?|MYpGMX YhCncc5};1_Lc(g@vtny z#E50yY}(w_OUASblXJB(q5Mq{YYVA8cOU+@F}eh%P)~h5{$6WR_?Q1 zMh_$W{;aAkdNjKU#4QX>Ze`t6wzYb`FAq2dgPZF4b?ivQ0Xh$C#DAoC{D^Muv(?{V z%yW&Tg@o3mhd;QZk~e=906?G_UkB~k7G1;DpT5+pZeLP@@HwWmMC`eW>%z6W>5$Y9 zCH%#0Cn2BPXS#?_Y8&w%pz(Q;{>Z!BG z-Q>#m-4_DpUr%gh`=F%70 |@{7pO*Wp1+H^HyiOhOlL7Kz@ |Vs(DxNye$7b(P2K zy+gox&m7zx+W&ZJzhy;39aNsI^6k0qy8_fbpsFf&Rt@sDJiPqV*@$hih?dGD)A?x6 zVTrAR@K62_a~w?x38R*;)%gBHgxJ1YL3ykV^V}j_OB{?TZeUOGM(=Oxf?==R^&txw zBOFh>`2!cIMjpC5U=hbcKAk_Lb|_dg(C3QgVg6Y6Y(emuq$0%5cwUH^MOWxAfYbOx zMI0M+*T@uyg?VsonOMn9F6g3L3GPkOzXbg~qUasI+#zZi(UBRg@arDm-M0#X1M$6B z3Dy$d_|rWki}B(=kVnI}V;X8Jwy IT{^I_q=&{KNb8_6fyD zNav6BQ<3wBp#a_LPUeH{Aej Qh*&4_B<&aGj{8oIMF_uzIibJB9k*svrugrXs z3l&^SVy~<1!q F1 b>^7Jq<3r6??P_*0h%Ro zwhU)ppVjHghE5A)2bb9SNi-xxN^`WgyJ;EgTTCGQ32Ps9iefvctKu}KQK35y#5w_M z(IA3S2E5EK%5rZ8YnX5*^vTRriSt_v7|pz6>9BpG&)chEBcGZXe*{sO%fa14;d|!g z{qhG1nyKPMf%z}(X;CD#B6`E$;q*IZQ`QL#pgBcX^L08uv~^etu^3jEupUfk-u;#h zHq>!l-(xHt0hA4c2^|JsDRA&Bq9(yeHJz3Vn=3)%3mB-0kJ d{w z`MPfi28!};KF1IOpv|t+K$~r`8c%`7e7G>s>%mom&|;v?o-6{XQ$5WWBa08Qqdgem~QS-{S#ke|W!qBEP3 zumhrroU{b+^vCwOy(9?$$N(7$QFYJk!&NVBY^@fNlcv-)tCmGkQEm*0?_{!^Rwg4j zoSU<~5``9+PMC!mBkA~D98$EMUtKI^&N!e2+cMcPJmNFFa4{4yDo#q+AbTEeI30w{ zqP?U2qopI#SOwHk)sHe{$2%M7yZjn%Q4x1nd?l~^kX5kZ$V2bK@4qnyf(YeV*+F8M zMrLH8R9%B_k!1ou1%VO)%ID-%a8ih3@1DiH3{8N?CqO1g`7>}r$d1tl_aY_%f44wh zws=uo)R$L$_I#2jr*XmaX8HM$K s-W{GAJ?5u{0Apd_AXIn82;{ z`e<^zm-qxCW>vjQ&)$fuT{qNRHg416P 5sv&?lTMzNx;XD{wQ2mg%&e`| zKm2?ZX+Ht^!T0ifjL$JAMNPt)4h SoOqtzhfhGz?@}6Qu!l}Dkq>jU2`yKPF2Wb45o`~=VxyPks%@LB)pB9H)4#M_( zEyJx|bIJ1ObV|-|&$<_hrqwSk*jn4#OI)Yl&=fbeyM}^S20N2%UtdcuUpEi~? l}pHJ zB=jtTjzyJ`_C=N_KmgqD!S|pjH_I2MV6`DfcW|{ke*B>{dC#qQ`WEyWD!EK6Q;Kgm z)N!0a_}Cz^1&NdetZF}sF259ToztSdc6;w)9V18{xbG?-8eSa)4oVWY_AvmuvXK{; z!E^iE tmf0T6QKk5K zL 6GTJ2(o;N*>1l0z7ARWWseox6Q zSX1u)=<(s7|MgJ3!oPO9xh6exUTEeg*htG?J<;=UtdXqgmYe~n zpH3cg)?{6J^!bra<%xA?piS}aimoM2Nj|2VMmZNggr5GMkk%Ms29s4P^N-;d>X_ri zoC0{DY~ihho_-`T5iv7)LMbL
7d9CI~ HXpwF%LnVSYvyVVunb!iw0}E&^x%}={hIil zVW04}0)bl;8(r||$P=^9xYl_V!=;{wi$_e;7&J$0PKdv8#<5fx@nSOZ#S7tS9ZEqN z(NK}RntELUb_%wHN7nV0&&jdZC1Z1Ec@R5h2-asBI3p-RS%etD9@oiu2 irnNXtKdCT8`Ha0r%+2_1Rc3I0Vk{ hw|Uu!ca=JW&yOnv+0-BlCB6gGKyr&r5gSPo zwfT%aM8(saoGl$5)UY0)&02LC%kC}iTMt1&OIL2j0ZV0XtyuRh&4`<)s7fM#)3E@9 z&0nrHhNbT4II6f;tr`{4=EsN+x16h7b2?_bi>Tm19*tiYI))Xp$&R#%GwL<8R&7wv zn(eKvQt__!=M2l)yjmw+OnfPPlL5!#mFg#1Ea1!bJd({8BWA=fUAGgCmP2MdZj+#h zIj^5>Uwyatc5A`*R%Fi>w((|PjGVWA1^t2=8&AJadjF;D4Dti!h0Bf0^4?O;&i>(g zfNSmcrW)6eWmjwdhx~$6on;pLv5rZ%G>>?Vk}tS%XBw-!n4zNC&)R(v7&cd z)#kmUa4E%o`VhR;8tuXu`(Z~t-iz{jxXl}&voTUkB>;Y!WspO3Ias2`wDQ0Fz?+th zPp#*TtD`R2k9OhN!gi_~O}+8|F1Ma+P|4Amq$YG!aevIXbae3yL|A{fIJ8T(nfQ3W zgrefl0C<`kE@nwH7|OjW&Yt7-JNCTnFOLdgG${#h)eh26^rp;mtMFQ{#RqOKC7uFu zTW<%R2saj59^dK|Mz+^G6trKT{^BVb56~B6nX}w$heP?ExzKbboFT$sk*-%_8h4?x zMtXGWCR*6O+KXb+qS)!Ai45G+*9Bwsc3-0CQum?$D#)2PSkTMvwCK)3A{7gn>=HCn zh&!v@K>$VwAfwe{Zngt-n@F@a+!h*ULhEV<$@@%ckdZi+kg(%QGaLW*k|;%zLli)% zAF2 p1%#(m<}c`#L*)`88_qzat9wl4^=Vmr(L}bKyW{;WaP@ieAw5N zus6!iFKtWWCm85~&+kkwLqri~i=!;$s*ogL|6ICecwXzsX}gpR9Kcv#^(segDzkE0 zDf%RxxL|JsIoiWuw1Si0e+8Pwc7A;7rgN6J;}Gsi- Fskc_P`~doyN33kT#UJ%vv;}lugUc`{`M*^rKJ! zus1bc8|om&%_p}oq9{aiV0VUMP0Fc7bDO1h^3k@nnjobP)cOt(UaUD(G8UI{;izZP z#5g{k&4I$JS`W(Z!<$G6=nIj3^gfR+*`pRA=~7=>m5 {_+$_>$}fcq8GZ^0pEdGB#-tz z2b9IUlFWY_j+-0Udvnf77k)lKcOYg;X5<-t%F=rpx*#KUgPx8yIy^UreHX9<65oFZ zbRDp*0iQKg$qk~2nC6<_URJDz)zU<(hSyn4vZ%9sGOj(1h}O$CBq06jzT)rKMD<;y zYN*-HL#4iR`G%}vX7$ih^j^!rZ>aroOgtVoIrPR$IpE7Hy@$&T@?m#8>02-p;j!Mz zVEHH=CGrh4AOh}fpcEpoJU-*~b@!bXx &khy&JbaokVjLdkHY_ zR7PH>knjVJU%wVrj$WDh?tt}_6fOezD(ZiXz!HnxF&b-KHw1~%VAT*2kWtBn&3G-| zxyCT;shv4$54Y%U{XE5Ax715Em8ni=B%YY0%Q|#14?Ugw{CX6)H_)L&xy$-50S*eG zI?Y~wk(Xk-cwr#Pnrqb%<=F4r`CnSLgXw}(@RI9)=SpfsFnbGV+sx@(q*8i3pJM zTl1IWP-?b&<8|UiEyt(WlzPGbFJmS^;T3-r@;B9>|A&+~K$YeKvb$#y1742H_kEEH z!FfES2&Hm7^&+?-@w_$?c!lPk{_4L_;cuEVG0jf{s}OTBFrVuu%lzQ ?_j`w6d5P0cT`LT!dyA~ z(S99ss$t{b!$Lge+MlqnwAWXTa8%cQbSL}iAxUc>{=Bb9X<}k>T)=*O#h*FRbElx4 zK8-#cbcb=l!T##K dOz-qcw9BNMDT6=;^F8+4~Oy-12stLui=#ZifgSUwOx zuDE}1Jg*&ne30I$AkAx{4zQPHv_RKzth*xQ$!m07-C7m2l`Zy4-dWWhtDmEizpFiL ziWs@Qyf4AC+w5RHm}r= *010a$Pw z#f74a>$2&sj659)oL{U;K?_cKMomm?mgS_=hhy&rz;jN9^?ruS{-G~I5>7hpZR6Ns zH*Mfc-CEp+J4_|Nm?lam4~$X0@{OVyiiQu=a!%(N*EN(=S5;g*G01h>q#yo%yZ=qp z!&^!d#Q5?xSs&xL)x#<>u;4jVd&bJa5krzsKA&eqNN_s!f%7Vn zg~TFPq<17b89eMARW({t!MKTYEcoSFV1b44DqC@N2I-F6!#|}55J04;?TNuGQb