*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows),0 3px 0 var(--tw-prose-kbd-shadows);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:rgba(17,24,39,.1);--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:hsla(0,0%,100%,.1);--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.sticky{position:sticky}.top-0{top:0}.isolate{isolation:isolate}.z-50{z-index:50}.m-0{margin:0}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.my-6{margin-top:1.5rem;margin-bottom:1.5rem}.my-8{margin-top:2rem;margin-bottom:2rem}.-mt-4{margin-top:-1rem}.mb-0{margin-bottom:0}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mr-2{margin-right:.5rem}.mt-0{margin-top:0}.mt-1{margin-top:.25rem}.mt-16{margin-top:4rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.h-4{height:1rem}.h-48{height:12rem}.h-auto{height:auto}.w-4{width:1rem}.w-full{width:100%}.min-w-\[600px\]{min-width:600px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-none{max-width:none}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.border-collapse{border-collapse:collapse}.list-none{list-style-type:none}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.rounded-r-xl{border-top-right-radius:.75rem;border-bottom-right-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-4{border-left-width:4px}.border-t-4{border-top-width:4px}.border-accent{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-con-border{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-ftc-border{--tw-border-opacity:1;border-color:rgb(245 158 11/var(--tw-border-opacity,1))}.border-pro-border{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity,1))}.border-slate-100{--tw-border-opacity:1;border-color:rgb(241 245 249/var(--tw-border-opacity,1))}.border-slate-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1))}.border-slate-300{--tw-border-opacity:1;border-color:rgb(203 213 225/var(--tw-border-opacity,1))}.border-l-accent{--tw-border-opacity:1;border-left-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-t-accent{--tw-border-opacity:1;border-top-color:rgb(37 99 235/var(--tw-border-opacity,1))}.bg-accent{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-con-bg{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-cta{--tw-bg-opacity:1;background-color:rgb(255 153 0/var(--tw-bg-opacity,1))}.bg-ftc-bg{--tw-bg-opacity:1;background-color:rgb(255 251 225/var(--tw-bg-opacity,1))}.bg-primary{--tw-bg-opacity:1;background-color:rgb(15 23 42/var(--tw-bg-opacity,1))}.bg-pro-bg{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-slate-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-16{padding-bottom:4rem}.pb-2{padding-bottom:.5rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.text-accent{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-con-text{--tw-text-opacity:1;color:rgb(153 27 27/var(--tw-text-opacity,1))}.text-ftc-text{--tw-text-opacity:1;color:rgb(120 53 15/var(--tw-text-opacity,1))}.text-primary{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.text-pro-text{--tw-text-opacity:1;color:rgb(22 101 52/var(--tw-text-opacity,1))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.text-slate-700{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.no-underline{text-decoration-line:none}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.hover\:bg-cta-hover:hover{--tw-bg-opacity:1;background-color:rgb(230 138 0/var(--tw-bg-opacity,1))}.hover\:bg-slate-100:hover{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.hover\:bg-slate-50:hover{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.hover\:text-accent:hover{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.group:hover .group-hover\:text-accent{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:flex-row{flex-direction:row}}@media (min-width:768px){.md\:mx-auto{margin-left:auto;margin-right:auto}.md\:w-1\/3{width:33.333333%}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:rounded-r-lg{border-top-right-radius:.5rem;border-bottom-right-radius:.5rem}.md\:p-10{padding:2.5rem}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}}/* ==========================================================================
   techpicksio.com — UI Design Layer  v1.0
   --------------------------------------------------------------------------
   Hand-authored, appended AFTER the compiled Tailwind build (src/tailwind.build.css).
   Because it loads later at equal specificity, it re-points the Tailwind colour
   utilities already used across the site at theme tokens. That means every page
   becomes theme-aware WITHOUT touching a single existing class name.

   Build:  ./build.sh   (cat src/tailwind.build.css src/techpicksio-ui.css > style.css)
   No npm, no node, no build tools required.

   Contents
     1. Design tokens (light / dark)
     2. Tailwind utility re-mapping
     3. Typography & prose
     4. Components (header, hero, cards, verdict, TOC, tables, pros/cons, CTA, footer)
     5. Motion, focus & print
   ========================================================================== */

/* ==========================================================================
   1. DESIGN TOKENS
   Values are space-separated RGB channels so they compose with Tailwind's
   `--tw-*-opacity` variables:  rgb(var(--surface) / var(--tw-bg-opacity, 1))
   ========================================================================== */

:root {
  color-scheme: light;

  /* Surfaces */
  --canvas:      246 247 250;   /* page background            */
  --surface:     255 255 255;   /* cards, header              */
  --surface-2:   241 245 249;   /* inset panels, hover fills  */
  --line:        226 232 240;   /* default border             */
  --line-soft:   241 245 249;   /* hairline border            */

  /* Text */
  --ink:          15  23  42;   /* headings          10.4:1 on surface */
  --body:         51  65  85;   /* body copy          9.6:1 on surface */
  --muted:        94 109 131;   /* meta, captions — 5.3:1 on surface, 4.9:1 on canvas */

  /* Brand */
  --accent:       37  99 235;   /* accent FILLS (white text sits on it) */
  --accent-fg:    29  78 216;   /* accent TEXT + borders on light bg    */
  --accent-soft: 239 246 255;   /* accent tint panel                    */

  /* Commercial */
  --cta:         255 153   0;   /* Amazon orange                        */
  --cta-hover:   230 138   0;
  --cta-ink:      15  23  42;   /* label colour on the orange button    */

  /* Verdict / pros / cons */
  --pro-bg:      240 253 244;
  --pro-border:  187 247 208;
  --pro-text:     21 128  61;
  --con-bg:      254 242 242;
  --con-border:  254 202 202;
  --con-text:    185  28  28;

  /* FTC disclosure */
  --ftc-bg:      255 251 225;
  --ftc-border:  245 158  11;
  --ftc-text:    120  53  15;

  /* Chrome */
  --footer-bg:    15  23  42;
  --footer-accent: 56 189 248;  /* bright on the dark footer in BOTH themes */
  --header-bg:   255 255 255;
  --shadow-color:  15 23 42;
  --shadow-strength: 0.06;

  /* Product photo plate — see 4.15. Light theme is a deliberate no-op:
     the plate is the card colour and brightness is unchanged. */
  --plate:            255 255 255;
  --plate-ring:       226 232 240;
  --plate-pad:        0.75rem;
  --plate-brightness: 1;

  /* Scale */
  --measure: 68ch;              /* 65–75 character reading column */
  --radius:  0.875rem;
  --radius-lg: 1.25rem;
}

/* Dark theme — applies on explicit choice, or by system preference when the
   visitor has not chosen. Both selectors are defined so the site is correct
   with JavaScript disabled. */
:root[data-theme="dark"] { color-scheme: dark; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark; }
}

:root[data-theme="dark"],
:root[data-theme="dark"] * {
  --shadow-strength: 0.55;
}

/* The token block is duplicated for the two dark selectors on purpose:
   CSS has no way to alias a selector list into a media query. */
:root[data-theme="dark"] {
  --canvas:        9  12  18;
  --surface:      18  24  33;
  --surface-2:    26  34  47;
  --line:         39  51  68;
  --line-soft:    30  40  54;

  --ink:         241 245 249;
  --body:        203 213 225;
  --muted:       148 163 184;

  --accent:        3 105 161;   /* white label on this = 6.1:1 */
  --accent-fg:    56 189 248;   /* bright cyan for text/borders */
  --accent-soft:  12  33  48;

  --cta:         255 153   0;
  --cta-hover:   255 176  51;
  --cta-ink:      12  16  23;

  --pro-bg:       13  38  27;
  --pro-border:   22  84  55;
  --pro-text:     74 222 128;
  --con-bg:       43  21  23;
  --con-border:  107  36  38;
  --con-text:    252 165 165;

  --ftc-bg:       34  26   8;
  --ftc-border:  245 158  11;
  --ftc-text:    252 211  77;

  --plate:      255 255 255;
  --plate-ring:    39  51  68;
  --plate-pad:    0.75rem;
  --plate-brightness: 0.88;
  --footer-bg:    13  17  24;
  --footer-accent: 56 189 248;
  --header-bg:    14  19  27;
  --shadow-color:  0   0   0;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --canvas:        9  12  18;
    --surface:      18  24  33;
    --surface-2:    26  34  47;
    --line:         39  51  68;
    --line-soft:    30  40  54;

    --ink:         241 245 249;
    --body:        203 213 225;
    --muted:       148 163 184;

    --accent:        3 105 161;
    --accent-fg:    56 189 248;
    --accent-soft:  12  33  48;

    --cta:         255 153   0;
    --cta-hover:   255 176  51;
    --cta-ink:      12  16  23;

    --pro-bg:       13  38  27;
    --pro-border:   22  84  55;
    --pro-text:     74 222 128;
    --con-bg:       43  21  23;
    --con-border:  107  36  38;
    --con-text:    252 165 165;

    --ftc-bg:       34  26   8;
    --ftc-border:  245 158  11;
    --ftc-text:    252 211  77;

    --plate:            255 255 255;
    --plate-ring:        39  51  68;
    --plate-pad:        0.75rem;
    --plate-brightness: 0.88;
    --footer-bg:    13  17  24;
    --footer-accent: 56 189 248;
    --header-bg:    14  19  27;
    --shadow-color:  0   0   0;
    --shadow-strength: 0.55;
  }
}

/* ==========================================================================
   2. TAILWIND UTILITY RE-MAPPING
   Existing markup keeps its class names; the colours become themeable.
   ========================================================================== */

/* --- Backgrounds --------------------------------------------------------- */
.bg-white      { background-color: rgb(var(--surface)   / var(--tw-bg-opacity, 1)); }
.bg-slate-50   { background-color: rgb(var(--canvas)    / var(--tw-bg-opacity, 1)); }
.bg-slate-100  { background-color: rgb(var(--surface-2) / var(--tw-bg-opacity, 1)); }
.bg-slate-200  { background-color: rgb(var(--line)      / var(--tw-bg-opacity, 1)); }
.hover\:bg-slate-50:hover  { background-color: rgb(var(--surface-2) / var(--tw-bg-opacity, 1)); }
.hover\:bg-slate-100:hover { background-color: rgb(var(--line)      / var(--tw-bg-opacity, 1)); }

/* --- Text ---------------------------------------------------------------- */
.text-primary,
.text-slate-900,
.text-slate-800 { color: rgb(var(--ink)   / var(--tw-text-opacity, 1)); }
.text-slate-700,
.text-slate-600 { color: rgb(var(--body)  / var(--tw-text-opacity, 1)); }
.text-slate-500,
.text-slate-400 { color: rgb(var(--muted) / var(--tw-text-opacity, 1)); }

/* --- Borders ------------------------------------------------------------- */
.border-slate-200,
.border-slate-300 { border-color: rgb(var(--line)      / var(--tw-border-opacity, 1)); }
.border-slate-100 { border-color: rgb(var(--line-soft) / var(--tw-border-opacity, 1)); }

/* --- Brand --------------------------------------------------------------- */
.bg-primary            { background-color: rgb(var(--footer-bg) / var(--tw-bg-opacity, 1)); }
.bg-accent             { background-color: rgb(var(--accent)    / var(--tw-bg-opacity, 1)); }
.text-accent,
.hover\:text-accent:hover,
.group:hover .group-hover\:text-accent { color: rgb(var(--accent-fg) / var(--tw-text-opacity, 1)); }
.border-accent,
.border-t-accent       { border-color: rgb(var(--accent-fg) / var(--tw-border-opacity, 1)); }

/* --- Pros / cons / FTC --------------------------------------------------- */
.bg-pro-bg      { background-color: rgb(var(--pro-bg)     / var(--tw-bg-opacity, 1)); }
.border-pro-border { border-color: rgb(var(--pro-border)  / var(--tw-border-opacity, 1)); }
.text-pro-text  { color: rgb(var(--pro-text)              / var(--tw-text-opacity, 1)); }
.bg-con-bg      { background-color: rgb(var(--con-bg)     / var(--tw-bg-opacity, 1)); }
.border-con-border { border-color: rgb(var(--con-border)  / var(--tw-border-opacity, 1)); }
.text-con-text  { color: rgb(var(--con-text)              / var(--tw-text-opacity, 1)); }
.bg-ftc-bg      { background-color: rgb(var(--ftc-bg)     / var(--tw-bg-opacity, 1)); }
.border-ftc-border { border-color: rgb(var(--ftc-border)  / var(--tw-border-opacity, 1)); }
.text-ftc-text  { color: rgb(var(--ftc-text)              / var(--tw-text-opacity, 1)); }

/* --- CTA buttons ---------------------------------------------------------
   Declaring `color` here also overrides the `text-slate-900` utility already
   on those anchors (same specificity, later source order), so the orange
   button keeps a legible dark label in dark mode with no markup change. */
.bg-cta {
  background-color: rgb(var(--cta) / var(--tw-bg-opacity, 1));
  color: rgb(var(--cta-ink) / 1);
}
.hover\:bg-cta-hover:hover { background-color: rgb(var(--cta-hover) / var(--tw-bg-opacity, 1)); }

/* --- Shadows -------------------------------------------------------------
   Tailwind's default shadows vanish on dark surfaces; these scale with theme. */
.shadow-sm { box-shadow: 0 1px 2px 0 rgb(var(--shadow-color) / var(--shadow-strength)); }
.shadow    { box-shadow: 0 1px 3px 0 rgb(var(--shadow-color) / var(--shadow-strength)),
                         0 1px 2px -1px rgb(var(--shadow-color) / var(--shadow-strength)); }
.shadow-md { box-shadow: 0 4px 6px -1px rgb(var(--shadow-color) / var(--shadow-strength)),
                         0 2px 4px -2px rgb(var(--shadow-color) / var(--shadow-strength)); }
.hover\:shadow-md:hover { box-shadow: 0 10px 20px -6px rgb(var(--shadow-color) / calc(var(--shadow-strength) * 2)); }

/* --- Utility top-ups -----------------------------------------------------
   The Tailwind build in src/tailwind.build.css is frozen: it only contains the
   utilities that were in use when it was compiled. Anything new the redesign
   needs is declared here. Run ./check-classes.py after editing markup to find
   classes that resolve to nothing. */
.max-w-6xl { max-width: 72rem; }
.mt-6      { margin-top: 1.5rem; }
.mt-3      { margin-top: 0.75rem; }
.pt-5      { padding-top: 1.25rem; }
.pb-1      { padding-bottom: 0.25rem; }
.flex-wrap { flex-wrap: wrap; }
.gap-3     { gap: 0.75rem; }
.gap-x-2   { -moz-column-gap: 0.5rem; column-gap: 0.5rem; }
.gap-y-1   { row-gap: 0.25rem; }

@media (min-width: 640px) { .sm\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 768px) { .md\:p-8 { padding: 2rem; } }

/* Used by existing article pages but never compiled — they were silently
   doing nothing before this layer existed. */
.my-4              { margin-top: 1rem; margin-bottom: 1rem; }
.rounded-r-lg      { border-top-right-radius: 0.5rem; border-bottom-right-radius: 0.5rem; }
.grid-cols-2       { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cursor-not-allowed { cursor: not-allowed; }

/* ==========================================================================
   3. TYPOGRAPHY & PROSE
   ========================================================================== */

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body { background-color: rgb(var(--canvas)); color: rgb(var(--body)); }

/* Anchor targets clear the sticky header instead of hiding under it. */
:target,
h2[id], h3[id] { scroll-margin-top: 6.5rem; }

/* Re-point the typography plugin at the theme tokens. */
.prose {
  --tw-prose-body:          rgb(var(--body));
  --tw-prose-headings:      rgb(var(--ink));
  --tw-prose-lead:          rgb(var(--body));
  --tw-prose-links:         rgb(var(--accent-fg));
  --tw-prose-bold:          rgb(var(--ink));
  --tw-prose-counters:      rgb(var(--muted));
  --tw-prose-bullets:       rgb(var(--line));
  --tw-prose-hr:            rgb(var(--line));
  --tw-prose-quotes:        rgb(var(--ink));
  --tw-prose-quote-borders: rgb(var(--accent-fg));
  --tw-prose-captions:      rgb(var(--muted));
  --tw-prose-th-borders:    rgb(var(--line));
  --tw-prose-td-borders:    rgb(var(--line));
  font-size: 1.0625rem;      /* 17px — comfortable long-form size  */
  line-height: 1.75;         /* inside the 1.6–1.8 target band     */
}
.prose :where(p, li) { text-wrap: pretty; }
.prose :where(h2, h3, h4) { text-wrap: balance; letter-spacing: -0.015em; }
.prose :where(h2) { font-size: 1.625rem; line-height: 1.25; margin-top: 2.5em; }
.prose :where(h3) { font-size: 1.25rem;  line-height: 1.35; margin-top: 1.9em; }
.prose :where(a):hover { text-decoration-thickness: 2px; }

/* Reading column: caps measure at ~68 characters without narrowing the
   full-bleed elements (tables, verdict box, cards) that need the room. */
.tpi-measure > p,
.tpi-measure > ul,
.tpi-measure > ol,
.tpi-measure > h2,
.tpi-measure > h3,
.tpi-measure > h4,
.tpi-measure > blockquote { max-width: var(--measure); }

/* ==========================================================================
   4. COMPONENTS
   ========================================================================== */

/* --- 4.1 Header ---------------------------------------------------------- */
.tpi-header {
  position: sticky; top: 0; z-index: 50;
  background-color: rgb(var(--header-bg) / 0.85);
  border-bottom: 1px solid rgb(var(--line));
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
}
.tpi-header__bar {
  max-width: 72rem; margin-inline: auto;
  display: flex; align-items: center; flex-wrap: wrap; gap: 0.75rem 1rem;
  padding: 0.75rem 1rem;
}
.tpi-header__brand { margin-right: auto; }
.tpi-wordmark {
  font-size: 1.375rem; font-weight: 800; letter-spacing: -0.03em;
  color: rgb(var(--ink)); line-height: 1.1;
  text-decoration: none; white-space: nowrap;
}
.tpi-wordmark span { color: rgb(var(--accent-fg)); }
.tpi-tagline {
  display: none; font-size: 0.75rem; color: rgb(var(--muted));
  margin-top: 0.125rem; letter-spacing: 0.01em;
}
@media (min-width: 768px) { .tpi-tagline { display: block; } }

/* Category rail — full-width scrollable second row on phones, inline on desktop.
   A gradient mask on the right edge signals that there is more to scroll. */
.tpi-nav {
  order: 3; flex: 0 0 100%;
  display: flex; gap: 0.25rem; align-items: center;
  padding-top: 0.5rem; border-top: 1px solid rgb(var(--line-soft));
  overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none;
  scroll-snap-type: x proximity;
  -webkit-mask-image: linear-gradient(90deg, #000 88%, transparent 100%);
          mask-image: linear-gradient(90deg, #000 88%, transparent 100%);
}
@media (min-width: 768px) {
  .tpi-nav {
    order: 0; flex: 0 1 auto; padding-top: 0; border-top: 0;
    -webkit-mask-image: none; mask-image: none;
  }
}
.tpi-nav::-webkit-scrollbar { display: none; }
.tpi-nav a {
  scroll-snap-align: start;
  display: flex; align-items: center; min-height: 2.75rem;   /* 44px tap target */
  padding: 0.5rem 0.75rem; border-radius: 999px;
  font-size: 0.8125rem; font-weight: 600; white-space: nowrap;
  color: rgb(var(--muted)); text-decoration: none;
  transition: color .15s ease, background-color .15s ease;
}
.tpi-nav a:hover { color: rgb(var(--ink)); background-color: rgb(var(--surface-2)); }
.tpi-nav a[aria-current="page"] { color: rgb(var(--accent-fg)); background-color: rgb(var(--accent-soft)); }

/* Theme toggle — 44px tap target, icon swaps by theme, no layout shift. */
.tpi-toggle {
  flex: none; width: 2.75rem; height: 2.75rem;
  display: inline-grid; place-items: center;
  border: 1px solid rgb(var(--line)); border-radius: 999px;
  background-color: rgb(var(--surface-2)); color: rgb(var(--ink));
  cursor: pointer; transition: background-color .15s ease, transform .15s ease;
}
.tpi-toggle:hover { background-color: rgb(var(--line)); }
.tpi-toggle:active { transform: scale(0.94); }
.tpi-toggle svg { width: 1.125rem; height: 1.125rem; }
.tpi-toggle .tpi-icon-sun  { display: none; }
:root[data-theme="dark"] .tpi-toggle .tpi-icon-sun  { display: block; }
:root[data-theme="dark"] .tpi-toggle .tpi-icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .tpi-toggle .tpi-icon-sun  { display: block; }
  :root:not([data-theme="light"]) .tpi-toggle .tpi-icon-moon { display: none; }
}

/* --- 4.2 Reading progress ------------------------------------------------
   CSS scroll-driven animation: zero JavaScript, GPU-composited transform.
   Browsers without support simply never show the bar (progressive enhancement). */
.tpi-progress {
  position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 60;
  transform-origin: 0 50%; transform: scaleX(0);
  background: linear-gradient(90deg, rgb(var(--accent-fg)), rgb(var(--cta)));
  pointer-events: none;
}
@supports (animation-timeline: scroll()) {
  .tpi-progress {
    animation: tpi-progress-grow linear both;
    animation-timeline: scroll(root block);
  }
}
@keyframes tpi-progress-grow { to { transform: scaleX(1); } }

/* --- 4.3 Hero --------------------------------------------------------------
   Centered, higher-contrast cinematic treatment: a diagonal accent-to-cta
   wash reads as a near-black gradient banner in dark mode (the surface it's
   layered on is already near-black) and as a bright, branded tint in light
   mode — same tokens, same component, no hardcoded "always dark" panel that
   would fight the site's light theme. */
.tpi-hero {
  position: relative; overflow: hidden;
  border: 1px solid rgb(var(--line)); border-radius: var(--radius-lg);
  background:
    linear-gradient(135deg, rgb(var(--accent) / 0.30) 0%, transparent 45%, rgb(var(--cta) / 0.24) 100%),
    radial-gradient(120% 140% at 12% 0%, rgb(var(--accent) / 0.22) 0%, transparent 55%),
    radial-gradient(90% 120% at 100% 10%, rgb(var(--cta) / 0.20) 0%, transparent 50%),
    rgb(var(--surface));
  padding: 2rem 1.25rem;
  text-align: center;
  display: flex; flex-direction: column; align-items: center;
}
@media (min-width: 768px) { .tpi-hero { padding: 4.5rem 2.5rem; } }
.tpi-hero__eyebrow {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: rgb(var(--accent-fg));
  background-color: rgb(var(--accent-soft));
  border: 1px solid rgb(var(--accent-fg) / 0.25);
  padding: 0.375rem 0.75rem; border-radius: 999px;
}
.tpi-hero__title {
  margin: 1rem 0 0.75rem; color: rgb(var(--ink));
  font-size: clamp(1.875rem, 1rem + 4.2vw, 3.75rem);
  font-weight: 800; letter-spacing: -0.03em; line-height: 1.1; text-wrap: balance;
  max-width: 20ch;
}
/* Wraps the clause that should read as the "headline within the headline" —
   e.g. <span class="tpi-hero__title-accent">compared on the numbers</span>.
   A gradient text fill, not a second color swatch, so it still passes as one
   design system rather than introducing a new token. */
.tpi-hero__title-accent {
  background-image: linear-gradient(100deg, rgb(var(--accent-fg)), rgb(var(--cta)));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.tpi-hero__sub { color: rgb(var(--body)); font-size: 0.9375rem; line-height: 1.6; max-width: 56ch; margin: 0 auto; }
@media (min-width: 768px) { .tpi-hero__sub { font-size: 1.125rem; line-height: 1.7; } }
.tpi-hero__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.875rem; margin-top: 1.75rem; }
.tpi-hero__actions .tpi-btn {
  border-radius: 999px; min-height: 3.25rem; padding: 0.875rem 1.875rem; font-size: 1rem;
}
.tpi-hero__stats {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem;
  margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgb(var(--line));
  width: 100%; max-width: 34rem; justify-items: center; text-align: center;
}
@media (min-width: 768px) {
  .tpi-hero__stats { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem 2.5rem; margin-top: 2.25rem; padding-top: 1.75rem; max-width: none; }
}
.tpi-stat__num { display: block; font-size: 1.375rem; font-weight: 800; color: rgb(var(--ink)); letter-spacing: -0.02em; }
.tpi-stat__label { font-size: 0.75rem; color: rgb(var(--muted)); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }

/* --- 4.4 Cards ----------------------------------------------------------- */
.tpi-grid { display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
@media (min-width: 640px) { .tpi-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .tpi-grid { grid-template-columns: repeat(3, 1fr); } }

.tpi-card {
  display: flex; flex-direction: column; overflow: hidden;
  background-color: rgb(var(--surface));
  border: 1px solid rgb(var(--line)); border-radius: var(--radius);
  text-decoration: none;
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
  will-change: transform;
}
.tpi-card:hover {
  transform: translateY(-3px);
  border-color: rgb(var(--accent-fg) / 0.45);
  box-shadow: 0 14px 30px -12px rgb(var(--shadow-color) / calc(var(--shadow-strength) * 2.2));
}
.tpi-card__media {
  position: relative; aspect-ratio: 16 / 10; background-color: rgb(var(--surface-2));
  /* min-height: 0 defeats the flexbox "automatic minimum size": as a flex item in
     .tpi-card's column layout, this box would otherwise ignore its own aspect-ratio
     for any photo intrinsically taller than 16:10 and grow to fit the image's natural
     size instead, breaking row alignment. Confirmed on 8 of 12 homepage thumbnails. */
  min-height: 0;
}
.tpi-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Card thumbnails are cropped fills in a fixed 16/10 box, not matted cutouts,
   so they take the plate's dimming (see 4.15) but none of its geometry —
   padding or object-fit here would inflate the media box and break the row's
   alignment. Two-class selector so it wins over .tpi-plate if both ever land
   on the same image. */
.tpi-card__media img { filter: brightness(var(--plate-brightness)); }
.tpi-card__body { padding: 1.125rem 1.25rem 1.375rem; display: flex; flex-direction: column; flex: 1 1 auto; }
.tpi-card__title {
  margin: 0.625rem 0 0.5rem; font-size: 1.0625rem; font-weight: 700; line-height: 1.35;
  color: rgb(var(--ink)); letter-spacing: -0.015em; text-wrap: balance;
  transition: color .15s ease;
}
.tpi-card:hover .tpi-card__title { color: rgb(var(--accent-fg)); }
.tpi-card__dek { margin: 0; font-size: 0.875rem; line-height: 1.6; color: rgb(var(--muted)); }
.tpi-card__meta {
  margin-top: auto; padding-top: 1rem; font-size: 0.75rem; font-weight: 600;
  color: rgb(var(--muted)); display: flex; align-items: center; gap: 0.375rem;
}

/* Featured card spans the grid on wide screens. */
.tpi-card--featured { grid-column: 1 / -1; }
@media (min-width: 768px) {
  .tpi-card--featured { flex-direction: row; align-items: stretch; }
  .tpi-card--featured .tpi-card__media { flex: 0 0 46%; aspect-ratio: auto; }
  .tpi-card--featured .tpi-card__body { padding: 2rem; justify-content: center; }
  .tpi-card--featured .tpi-card__title { font-size: 1.625rem; line-height: 1.2; }
  .tpi-card--featured .tpi-card__dek { font-size: 1rem; }
}

/* --- 4.5 Badges ---------------------------------------------------------- */
.tpi-badge {
  display: inline-flex; align-items: center; gap: 0.375rem; align-self: flex-start;
  font-size: 0.6875rem; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase;
  padding: 0.3125rem 0.625rem; border-radius: 0.375rem;
  background-color: rgb(var(--accent)); color: #fff;
}
.tpi-badge--quiet {
  background-color: rgb(var(--surface-2)); color: rgb(var(--muted));
  border: 1px solid rgb(var(--line));
}
.tpi-badge--pick { background-color: rgb(var(--cta)); color: rgb(var(--cta-ink)); }

/* --- 4.5b Pending product photo ------------------------------------------
   Stands in for an <img> when no real product photo exists yet — e.g. an
   editorial pick without a sourced ASIN. Never a generated placeholder
   image: a labeled empty box is honest about missing content in a way a
   fake photo isn't. */
.tpi-img-pending {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 2 / 1; border-radius: var(--radius);
  background-color: rgb(var(--surface-2)); border: 1px dashed rgb(var(--line));
  color: rgb(var(--muted)); font-size: 0.875rem; font-weight: 600;
  margin-bottom: 2rem;
}
.tpi-img-pending--secondary { aspect-ratio: 16 / 9; margin: 1.5rem 0; }

/* --- 4.6 Verdict box (above-the-fold direct answer) ---------------------- */
.tpi-verdict {
  border: 1px solid rgb(var(--line)); border-top: 4px solid rgb(var(--accent-fg));
  border-radius: var(--radius);
  background:
    linear-gradient(180deg, rgb(var(--accent) / 0.07), transparent 60%),
    rgb(var(--surface-2));
  padding: 1.5rem; margin: 2rem 0;
}
.tpi-verdict h2 { margin: 0.75rem 0 0.5rem !important; font-size: 1.375rem; color: rgb(var(--ink)); }
.tpi-verdict p { margin: 0 0 1.25rem; color: rgb(var(--body)); max-width: var(--measure); }
.tpi-verdict__grid {
  display: grid; gap: 0.75rem; grid-template-columns: 1fr; margin: 1rem 0 1.25rem;
}
@media (min-width: 640px) { .tpi-verdict__grid { grid-template-columns: repeat(3, 1fr); } }
.tpi-fact {
  background-color: rgb(var(--surface)); border: 1px solid rgb(var(--line));
  border-radius: 0.625rem; padding: 0.75rem 0.875rem;
}
.tpi-fact dt { font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: rgb(var(--muted)); }
.tpi-fact dd { margin: 0.25rem 0 0; font-size: 0.9375rem; font-weight: 700; color: rgb(var(--ink)); }

/* --- 4.7 Sticky table of contents ---------------------------------------- */
.tpi-layout { display: block; }
@media (min-width: 1120px) {
  .tpi-layout { display: grid; grid-template-columns: minmax(0, 1fr) 15rem; gap: 3rem; align-items: start; }
}
.tpi-toc { display: none; }
@media (min-width: 1120px) {
  .tpi-toc {
    display: block; position: sticky; top: 6rem;
    border-left: 2px solid rgb(var(--line)); padding-left: 1rem;
  }
}
.tpi-toc__title { font-size: 0.6875rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: rgb(var(--muted)); margin-bottom: 0.75rem; }
.tpi-toc ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
/* Scoped to the list so it can never bleed into the sidebar CTA button. */
.tpi-toc ul a {
  display: block; font-size: 0.8125rem; line-height: 1.45;
  color: rgb(var(--muted)); text-decoration: none;
  border-left: 2px solid transparent; margin-left: -1.0625rem; padding-left: 0.9375rem;
  transition: color .15s ease, border-color .15s ease;
}
.tpi-toc ul a:hover { color: rgb(var(--accent-fg)); }
/* Scroll-spy: the link for the section currently in view. */
.tpi-toc ul a[aria-current="true"] {
  color: rgb(var(--ink)); font-weight: 600;
  border-left-color: rgb(var(--accent-fg));
}

/* Mobile: same links collapse into a native <details> disclosure. */
.tpi-toc-mobile {
  border: 1px solid rgb(var(--line)); border-radius: var(--radius);
  background-color: rgb(var(--surface-2)); padding: 0.875rem 1rem; margin: 1.5rem 0;
}
@media (min-width: 1120px) { .tpi-toc-mobile { display: none; } }
.tpi-toc-mobile > summary {
  cursor: pointer; min-height: 2.75rem; font-size: 0.8125rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: rgb(var(--ink)); list-style: none;
  display: flex; align-items: center; justify-content: space-between;
}
.tpi-toc-mobile > summary::-webkit-details-marker { display: none; }
.tpi-toc-mobile > summary::after { content: "+"; font-size: 1.25rem; line-height: 1; color: rgb(var(--muted)); }
.tpi-toc-mobile[open] > summary::after { content: "–"; }
.tpi-toc-mobile ul { list-style: none; margin: 0.875rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.625rem; }
.tpi-toc-mobile a {
  font-size: 0.9375rem; color: rgb(var(--body)); text-decoration: none;
  display: flex; align-items: center; min-height: 2.75rem;   /* 44px tap target */
}
.tpi-toc-mobile ul { gap: 0; }
.tpi-toc-mobile li + li { border-top: 1px solid rgb(var(--line-soft)); }

/* --- 4.8 Comparison tables ----------------------------------------------
   Desktop/tablet: scrollable with a frozen first column and a fade hint.
   ≤639px: each row reflows into a labelled card via data-label attributes. */
.tpi-table-wrap {
  position: relative; overflow-x: auto; -webkit-overflow-scrolling: touch;
  border: 1px solid rgb(var(--line)); border-radius: var(--radius);
  background-color: rgb(var(--surface)); margin: 2rem 0;
}
.tpi-table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }
.tpi-table th, .tpi-table td { padding: 0.875rem 1rem; text-align: left; vertical-align: top; }
.tpi-table thead th {
  position: sticky; top: 0; z-index: 2;
  background-color: rgb(var(--surface-2)); color: rgb(var(--ink));
  font-size: 0.75rem; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
  border-bottom: 1px solid rgb(var(--line)); white-space: nowrap;
}
.tpi-table tbody tr + tr td { border-top: 1px solid rgb(var(--line-soft)); }
.tpi-table tbody tr:hover td { background-color: rgb(var(--surface-2) / 0.6); }
.tpi-table td { color: rgb(var(--body)); }
.tpi-table th[scope="row"] {
  position: sticky; left: 0; z-index: 1;
  background-color: rgb(var(--surface)); color: rgb(var(--ink)); font-weight: 700;
  border-right: 1px solid rgb(var(--line-soft)); min-width: 11rem;
}
.tpi-table tbody tr:hover th[scope="row"] { background-color: rgb(var(--surface-2)); }

@media (max-width: 639px) {
  .tpi-table-wrap { border: 0; background: transparent; overflow: visible; }
  .tpi-table, .tpi-table tbody, .tpi-table tr, .tpi-table td, .tpi-table th { display: block; width: 100%; }
  .tpi-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .tpi-table tbody tr {
    background-color: rgb(var(--surface)); border: 1px solid rgb(var(--line));
    border-radius: var(--radius); margin-bottom: 1rem; overflow: hidden;
  }
  .tpi-table th[scope="row"] {
    position: static; background-color: rgb(var(--surface-2)); border-right: 0;
    border-bottom: 1px solid rgb(var(--line)); font-size: 1rem; min-width: 0;
  }
  .tpi-table tbody tr + tr td { border-top: 0; }
  .tpi-table td { display: flex; justify-content: space-between; gap: 1rem; padding: 0.625rem 1rem; }
  .tpi-table td + td { border-top: 1px solid rgb(var(--line-soft)); }
  .tpi-table td::before {
    content: attr(data-label);
    font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
    color: rgb(var(--muted)); flex: 0 0 40%;
  }
}

/* --- 4.8b FAQ accordion (native <details>, no JavaScript) ---------------- */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0;
}
details > summary { list-style: none; }
details > summary::-webkit-details-marker { display: none; }

.tpi-faq > details { border-bottom: 1px solid rgb(var(--line)); }
.tpi-faq > details > summary {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  padding: 1rem 0; min-height: 2.75rem; cursor: pointer;
  font-size: 1.0625rem; font-weight: 700; color: rgb(var(--ink)); line-height: 1.45;
}
.tpi-faq > details > summary:hover { color: rgb(var(--accent-fg)); }
.tpi-faq > details > summary::after {
  content: ""; flex: none; width: 0.625rem; height: 0.625rem; margin-top: 0.4rem;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform .2s ease;
}
.tpi-faq > details[open] > summary::after { transform: rotate(-135deg); }
.tpi-faq > details > p { margin: 0 0 1.125rem; color: rgb(var(--body)); line-height: 1.7; max-width: var(--measure); }

/* --- 4.8c Legacy article components --------------------------------------
   These class names already exist in the published articles but had no rules.
   Styling them here upgrades every existing page with no markup edits. */

/* `.dab` — Direct Answer Block. The concise, factual "quick take" paragraph
   that generative engines lift as the answer to a query. It should read as the
   most scannable element on the page. */
.dab {
  display: block;
  background:
    linear-gradient(90deg, rgb(var(--accent) / 0.08), transparent 60%),
    rgb(var(--surface-2)) !important;
  border-left: 4px solid rgb(var(--accent-fg)) !important;
  border-radius: 0 0.625rem 0.625rem 0 !important;
  padding: 1rem 1.125rem !important;
  margin: 1.5rem 0 !important;
  color: rgb(var(--ink)) !important;
  font-size: 1rem; line-height: 1.65;
}
.dab strong { color: rgb(var(--accent-fg)); }

/* `.table-container` — the existing comparison-table wrapper. Freeze the first
   column so product names stay visible while the specs scroll on a phone, and
   fade the right edge so it is obvious there is more to see. */
.table-container { position: relative; }
.table-container table { border-collapse: separate; border-spacing: 0; }
.table-container thead th:first-child,
.table-container tbody td:first-child,
.table-container tbody th:first-child {
  position: sticky; left: 0; z-index: 1;
  background-color: rgb(var(--surface));
  box-shadow: 1px 0 0 0 rgb(var(--line));
}
.table-container thead th:first-child { background-color: rgb(var(--surface-2)); z-index: 2; }
.table-container tbody tr:hover td:first-child { background-color: rgb(var(--surface-2)); }
@media (min-width: 900px) {
  /* Nothing to freeze once the table fits. */
  .table-container thead th:first-child,
  .table-container tbody td:first-child,
  .table-container tbody th:first-child { position: static; box-shadow: none; }
}

/* --- 4.8d Legacy header & footer -----------------------------------------
   Pages not yet migrated to .tpi-header / .tpi-footer use the old markup:
   a dark `.bg-primary` footer with `text-slate-400` links. Those utilities are
   re-mapped to --muted, which is tuned for LIGHT surfaces and drops to 3.4:1 on
   the dark footer. Restore a light muted and the bright accent inside the dark
   footer specifically. Delete this block once every page uses .tpi-footer. */
.bg-primary.text-slate-400,
.bg-primary.text-slate-500,
.bg-primary .text-slate-400,
.bg-primary .text-slate-500 { color: #94a3b8; }        /* 7.0:1 on the footer */
.bg-primary .text-accent    { color: rgb(var(--footer-accent)); }
.bg-primary p               { color: #94a3b8; }

/* The legacy "Back to Home" link is a 20px-tall tap target on phones. */
a.inline-flex.items-center { min-height: 2.75rem; }
@media (min-width: 769px) { a.inline-flex.items-center { min-height: 0; } }

/* Legacy CTA buttons render 32px tall (and in-table price links 20px), below the
   44px touch floor. Normalising them here fixes every unmigrated page at once and
   makes the primary conversion element easier to hit on a phone. */
a.bg-cta,
a.inline-block.mt-2,
.table-container a.inline-block {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 2.75rem;
}

/* Disabled "ASIN pending" button: readable, and obviously not clickable. */
.cursor-not-allowed {
  background-color: rgb(var(--surface-2)) !important;
  color: rgb(var(--body)) !important;
  border: 1px dashed rgb(var(--line));
}

/* --- 4.9 Pros & cons ----------------------------------------------------- */
.tpi-pc { display: grid; gap: 1rem; grid-template-columns: 1fr; margin: 2rem 0; }
@media (min-width: 768px) { .tpi-pc { grid-template-columns: repeat(2, 1fr); } }
.tpi-pc__panel { border-radius: var(--radius); padding: 1.25rem; border: 1px solid; }
.tpi-pc__panel--pro { background-color: rgb(var(--pro-bg)); border-color: rgb(var(--pro-border)); }
.tpi-pc__panel--con { background-color: rgb(var(--con-bg)); border-color: rgb(var(--con-border)); }
.tpi-pc__title {
  margin: 0 0 0.875rem; font-size: 0.8125rem; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase;
  display: flex; align-items: center; gap: 0.5rem;
}
.tpi-pc__panel--pro .tpi-pc__title { color: rgb(var(--pro-text)); }
.tpi-pc__panel--con .tpi-pc__title { color: rgb(var(--con-text)); }
.tpi-pc__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.625rem; }
.tpi-pc__list li {
  display: grid; grid-template-columns: 1.25rem 1fr; gap: 0.625rem;
  font-size: 0.9375rem; line-height: 1.55; color: rgb(var(--body));
}
.tpi-pc__list li svg { width: 1.125rem; height: 1.125rem; margin-top: 0.15rem; }
.tpi-pc__panel--pro .tpi-pc__list li svg { color: rgb(var(--pro-text)); }
.tpi-pc__panel--con .tpi-pc__list li svg { color: rgb(var(--con-text)); }

/* --- 4.10 Buttons -------------------------------------------------------- */
.tpi-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  min-height: 2.875rem;                  /* 46px — above the 44px tap floor */
  padding: 0.75rem 1.375rem; border-radius: 0.625rem;
  font-weight: 700; font-size: 0.9375rem; text-decoration: none; cursor: pointer;
  border: 1px solid transparent;
  transition: background-color .15s ease, transform .12s ease, box-shadow .15s ease;
}
.tpi-btn:active { transform: translateY(1px); }
.tpi-btn--cta {
  background-color: rgb(var(--cta)); color: rgb(var(--cta-ink));
  box-shadow: 0 6px 16px -8px rgb(var(--cta) / 0.9);
}
.tpi-btn--cta:hover { background-color: rgb(var(--cta-hover)); }
.tpi-btn--cta svg { width: 1rem; height: 1rem; }
.tpi-btn--ghost {
  background-color: rgb(var(--surface)); color: rgb(var(--ink)); border-color: rgb(var(--line));
}
.tpi-btn--ghost:hover { background-color: rgb(var(--surface-2)); border-color: rgb(var(--accent-fg) / 0.5); }
/* Unsized inline SVG defaults to its intrinsic (often huge) replaced-element box,
   which starves the label of width and forces it onto multiple lines inside a flex
   button — .tpi-btn--cta and --sm already size their own icons; ghost needs the
   same so a ghost button can safely carry a trailing/leading icon. */
.tpi-btn--ghost svg { width: 1rem; height: 1rem; flex: none; }
.tpi-btn--block { display: flex; width: 100%; }

/* Compact CTA for dense contexts — the Action cell of a comparison table, where
   the full-size button wraps onto three lines in a narrow product column. Trims
   the type and padding only; min-height still clears the 44px tap floor. */
.tpi-btn--sm {
  min-height: 2.75rem;                   /* 44px */
  padding: 0.5rem 0.875rem;
  font-size: 0.8125rem;
  gap: 0.375rem;
}
.tpi-btn--sm svg { width: 0.875rem; height: 0.875rem; }

/* --- 4.11 Sticky mobile CTA ---------------------------------------------
   Appears only on phones, only once the reader has scrolled past the hero. */
.tpi-stickybar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 55;
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.625rem 0.875rem calc(0.625rem + env(safe-area-inset-bottom));
  background-color: rgb(var(--surface) / 0.94);
  border-top: 1px solid rgb(var(--line));
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  transform: translateY(110%); transition: transform .25s ease;
}
.tpi-stickybar.is-visible { transform: translateY(0); }
@media (min-width: 768px) { .tpi-stickybar { display: none; } }
.tpi-stickybar__meta { flex: 1 1 auto; min-width: 0; }
.tpi-stickybar__label { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 700; color: rgb(var(--muted)); }
.tpi-stickybar__name { font-size: 0.875rem; font-weight: 700; color: rgb(var(--ink)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tpi-stickybar .tpi-btn { flex: 0 0 auto; padding-inline: 1rem; }
/* Keeps the footer clear of the bar on phones. */
@media (max-width: 767px) { body:has(.tpi-stickybar) { padding-bottom: 4.5rem; } }

/* --- 4.12 Back to top ---------------------------------------------------- */
.tpi-totop {
  position: fixed; right: 1rem; bottom: 1rem; z-index: 54;
  width: 2.75rem; height: 2.75rem; display: none; place-items: center;
  border-radius: 999px; border: 1px solid rgb(var(--line));
  background-color: rgb(var(--surface)); color: rgb(var(--ink));
  box-shadow: 0 8px 20px -8px rgb(var(--shadow-color) / 0.5);
  text-decoration: none;
}
@media (min-width: 768px) { .tpi-totop { display: grid; opacity: 0; pointer-events: none; transition: opacity .2s ease; } }
.tpi-totop.is-visible { opacity: 1; pointer-events: auto; }
.tpi-totop:hover { background-color: rgb(var(--surface-2)); }

/* --- 4.13 FTC disclosure ------------------------------------------------- */
.tpi-ftc {
  display: flex; gap: 0.75rem; align-items: flex-start;
  background-color: rgb(var(--ftc-bg)); color: rgb(var(--ftc-text));
  border: 1px solid rgb(var(--ftc-border) / 0.5); border-left: 4px solid rgb(var(--ftc-border));
  border-radius: 0.625rem; padding: 0.75rem 1rem;
  font-size: 0.8125rem; line-height: 1.55;
}
.tpi-ftc svg { flex: none; width: 1.125rem; height: 1.125rem; margin-top: 0.1rem; }

/* --- 4.13b Editorial byline --------------------------------------------------
   E-E-A-T block that closes every article. techpicksio.com has no named
   reviewer and does not test hardware in-house, so the byline is attributed
   to the publication rather than to an invented person, and the monogram
   stands in for the head-shot a first-party reviewer would carry. Inventing
   either would be exactly the kind of manufactured authority signal that
   references/compliance.md forbids.

   Its job is to state the sourcing plainly and hand the reader the
   methodology page, which is what both a human assessor and a generative
   engine look for when deciding how much weight the recommendation carries. */
.tpi-byline {
  display: flex; gap: 1rem; align-items: flex-start;
  margin: 2.5rem 0 0;
  padding: 1.125rem 1.25rem;
  background-color: rgb(var(--surface-2));
  border: 1px solid rgb(var(--line));
  border-radius: var(--radius);
}
.tpi-byline__mark {
  flex: none;
  display: grid; place-items: center;
  width: 3rem; height: 3rem;
  border-radius: 0.75rem;
  background-color: rgb(var(--accent));
  color: #fff;
  font-size: 0.9375rem; font-weight: 800; letter-spacing: -0.02em;
}
.tpi-byline__name {
  margin: 0 0 0.25rem;
  font-size: 0.9375rem; font-weight: 700; color: rgb(var(--ink));
}
.tpi-byline__role {
  margin: 0; font-size: 0.8125rem; line-height: 1.6; color: rgb(var(--body));
}
.tpi-byline__links {
  /* The 44px tap floor applies here too: these are the two links that carry a
     reader from a recommendation to the sourcing behind it, and they sit in a
     block that is otherwise all small type. Each anchor is given the height
     rather than the row, and the top margin is pulled back by the padding the
     anchors add, so the block does not grow taller than it reads. */
  margin: 0.25rem 0 -0.625rem; font-size: 0.8125rem; color: rgb(var(--muted));
  display: flex; flex-wrap: wrap; align-items: center;
  column-gap: 1.5rem; row-gap: 0;
}
.tpi-byline__links a {
  display: inline-flex; align-items: center; min-height: 2.75rem;
  color: rgb(var(--accent-fg)); font-weight: 600; text-decoration: none;
}
.tpi-byline__links a:hover { text-decoration: underline; }

/* --- 4.13c Checklist ---------------------------------------------------------
   A list the reader is meant to work down and, on the gear checklist page,
   physically tick off on paper. The empty square is drawn rather than being a
   real checkbox: a checkbox implies state the page cannot save, and an unsaved
   control that silently forgets what you clicked is worse than a printed box.

   Rows are given the same left rail as the pros/cons list so the three
   list-shaped components on the site read as one family. */
.tpi-checklist {
  list-style: none; margin: 1.25rem 0; padding: 0;
  display: flex; flex-direction: column; gap: 0.625rem;
}
.tpi-checklist li {
  display: flex; gap: 0.75rem; align-items: flex-start;
  background-color: rgb(var(--surface-2));
  border: 1px solid rgb(var(--line));
  border-radius: 0.625rem;
  padding: 0.75rem 0.9375rem;
  font-size: 0.9375rem; line-height: 1.6; color: rgb(var(--body));
}
.tpi-checklist li svg {
  flex: none; width: 1.125rem; height: 1.125rem; margin-top: 0.15rem;
  color: rgb(var(--accent-fg));
}
.tpi-checklist strong { color: rgb(var(--ink)); }
.tpi-checklist a { color: rgb(var(--accent-fg)); font-weight: 600; }

/* --- 4.13d Silo uplink -------------------------------------------------------
   One quiet line under each verdict box pointing a first-time buyer back up to
   the starter-kit hub. It is deliberately the least prominent element in that
   part of the page: the reader who already knows they want a cage should not
   have their eye pulled off the recommendation they came for. Muted text, no
   panel, no icon — only the link itself carries accent colour. */
.tpi-uplink {
  margin: 1.25rem 0 0;
  font-size: 0.875rem; line-height: 1.6; color: rgb(var(--muted));
}
.tpi-uplink a { color: rgb(var(--accent-fg)); font-weight: 600; }

/* --- 4.14 Footer --------------------------------------------------------- */
.tpi-footer {
  background-color: rgb(var(--footer-bg)); color: #94a3b8;
  border-top: 3px solid rgb(var(--accent-fg));
  padding: 3rem 1rem 2.5rem; font-size: 0.875rem;
}
.tpi-footer a { color: #cbd5e1; text-decoration: none; }
.tpi-footer a:hover { color: #fff; text-decoration: underline; }
.tpi-footer__inner { max-width: 72rem; margin-inline: auto; }
.tpi-footer__cols { display: grid; gap: 2rem; grid-template-columns: 1fr; }
@media (min-width: 768px) { .tpi-footer__cols { grid-template-columns: 2fr 1fr 1fr; } }
.tpi-footer__mark {
  color: #fff; font-size: 1.5rem; font-weight: 800;
  letter-spacing: -0.03em; margin-bottom: 0.75rem;
}
.tpi-footer__mark span { color: rgb(var(--footer-accent)); }
.tpi-footer__head { color: #fff; font-weight: 700; font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 0.875rem; }
.tpi-footer__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.625rem; }
.tpi-footer__legal { margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid rgb(255 255 255 / 0.1); font-size: 0.75rem; line-height: 1.7; color: #7c8a9c; }

/* --- 4.15 Section headings ----------------------------------------------- */
.tpi-section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin: 2.5rem 0 1.25rem; }
.tpi-section-head h2 { margin: 0; font-size: 1.375rem; font-weight: 800; letter-spacing: -0.02em; color: rgb(var(--ink)); }
.tpi-section-head p { margin: 0.25rem 0 0; font-size: 0.875rem; color: rgb(var(--muted)); }

/* --- 4.14 Skip link ------------------------------------------------------
   WCAG 2.4.1 Bypass Blocks. Eight controls — the wordmark, five category
   links and the theme toggle — precede the content on every page, so without
   this a keyboard or screen-reader user tabs the whole header again on every
   navigation. Parked off-canvas until focused, then pinned above the sticky
   header (z-index 50) and the progress bar (60). */
.tpi-skip {
  position: fixed; top: 0.75rem; left: 0.75rem; z-index: 70;
  transform: translateY(-200%);
  display: inline-flex; align-items: center;
  min-height: 2.75rem; padding: 0.75rem 1.25rem;
  border-radius: 0.625rem;
  background-color: rgb(var(--accent)); color: #fff;
  font-size: 0.9375rem; font-weight: 700; text-decoration: none;
  box-shadow: 0 12px 28px -12px rgb(var(--shadow-color) / 0.7);
  transition: transform .15s ease;
}
.tpi-skip:focus { transform: translateY(0); }

/* <main> carries tabindex="-1" purely so that following the skip link moves
   FOCUS and not just scroll position. It is not an interactive control, so a
   focus ring around the entire content column would read as a rendering bug
   rather than as feedback. This is the one place an outline is suppressed. */
main[tabindex="-1"]:focus { outline: none; }

/* --- 4.15 Product photo plate ---------------------------------------------
   Every product shot in the library is a white-background cutout — measured
   border luminance 247-255 across all 31 files, no lifestyle shots. On the
   light theme those sit invisibly on a white card. On the dark theme a raw
   cutout is a 255-white rectangle punched into a near-black page, and it is
   the one place the cinematic treatment visibly breaks.

   The plate makes that rectangle deliberate rather than accidental: the
   cutout is matted onto neutral paper of the same tone, given a hairline
   edge, and dimmed in dark mode so it reads as lit paper instead of a light
   box. Because the mat and the cutout background are the same white, the
   join is seamless and the dimming applies to both at once — there is no
   inner rectangle. object-fit is contain so the mat can never crop or
   squash the product, which matters on an affiliate page where the photo is
   the product claim.

   Padding is identical in both themes so toggling the theme never reflows an
   image; only the ring colour and the brightness change.

   Applies to article images only. Card thumbnails are handled in 4.4 with
   the dimming alone — see the note there. */
.tpi-plate {
  background-color: rgb(var(--plate));
  padding: var(--plate-pad);
  object-fit: contain;
  border: 1px solid rgb(var(--plate-ring));
  filter: brightness(var(--plate-brightness));
}

/* Comparison image captions — a side-by-side product image block (as in a
   head-to-head intro) has no other way to tell a skimmer, or a generative
   engine, which photo is which without reading further down the page. The
   figcaption labels the photo; it must stay quiet so it never competes with
   the verdict badge that follows it. Wrap each image in a <figure> so the
   caption stacks under its own image, not between them, when the pair
   reflows to one column on narrow screens. */
.tpi-compare__item { margin: 0; }
.tpi-compare-caption {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.6;
  font-weight: 600;
  color: rgb(var(--muted));
  text-align: center;
}

/* --- 4.16 Multi-network CTA group -----------------------------------------
   A product listed on more than one affiliate network gets one button per
   network instead of one bare "check price" button. Only one button in the
   group carries `.tpi-btn--cta` (the orange fill) — the network judged the
   best link for that product; the rest use `.tpi-btn--ghost` so the row
   reads as one clear primary action with secondary options, not three
   buttons competing for the click. Wraps to a stacked column on phones so
   no button drops under the 44px tap floor from being squeezed. */
.tpi-cta-group {
  display: flex; flex-wrap: wrap; gap: 0.75rem;
  margin: 1.25rem 0;
}
.tpi-cta-group .tpi-btn { flex: 1 1 auto; }
@media (max-width: 479px) { .tpi-cta-group .tpi-btn { flex: 1 1 100%; } }

/* --- 4.17 Store hero (category storefronts) --------------------------------
   Same tokens and gradient as the homepage hero (4.3) — the Lifestyle Tech
   silo is a new content section, not a new visual brand, so it must read as
   the same site. `--store` only tightens vertical rhythm slightly, since a
   storefront page leads straight into a category grid rather than a stats
   row. */
.tpi-hero--store { padding-bottom: 1.75rem; }
@media (min-width: 768px) { .tpi-hero--store { padding-bottom: 2.25rem; } }
.tpi-hero--store .tpi-hero__title { margin-bottom: 0.5rem; }

/* --- 4.18 Promo banner ------------------------------------------------------
   Points at one real, currently-listed bundle or deal page — never a
   fabricated discount code or countdown. No urgency mechanics belong here;
   the badge is editorial ("Bundle"), not a claim about scarcity or time. */
.tpi-promo {
  display: flex; flex-wrap: wrap; gap: 1.25rem; align-items: center; justify-content: space-between;
  background:
    linear-gradient(180deg, rgb(var(--cta) / 0.08), transparent 70%),
    rgb(var(--surface));
  border: 1px solid rgb(var(--line)); border-radius: var(--radius);
  padding: 1.25rem 1.5rem; margin: 2rem 0;
}
.tpi-promo__body { flex: 1 1 20rem; }
.tpi-promo__title { margin: 0.5rem 0 0.375rem; font-size: 1.125rem; font-weight: 800; color: rgb(var(--ink)); letter-spacing: -0.015em; }
.tpi-promo__body p { margin: 0; font-size: 0.9375rem; line-height: 1.6; color: rgb(var(--body)); }
.tpi-promo .tpi-btn { flex: none; }

/* --- 4.19 Badge modifiers ---------------------------------------------------
   Editorial categorization only — see references/compliance.md. These never
   pair with a star rating, a score, or "tested" language; they say what kind
   of pick this is, not how it performed in hands-on testing. */
.tpi-badge--editors-choice { background-color: rgb(var(--cta)); color: rgb(var(--cta-ink)); }
.tpi-badge--budget-pick { background-color: rgb(var(--pro-bg)); color: rgb(var(--pro-text)); border: 1px solid rgb(var(--pro-border)); }
.tpi-badge--pro-gear { background-color: rgb(var(--accent-soft)); color: rgb(var(--accent-fg)); border: 1px solid rgb(var(--accent-fg) / 0.35); }

/* --- 4.20 Numbered pick badge ------------------------------------------------
   For "Top 5" / "Ranked Essentials" grids. A plain numeral on the existing
   surface/ink tokens — not a star, not a score, just the list position. */
.tpi-card { position: relative; }
.tpi-rank {
  position: absolute; top: 0.75rem; left: 0.75rem; z-index: 1;
  display: grid; place-items: center;
  width: 1.75rem; height: 1.75rem; border-radius: 999px;
  background-color: rgb(var(--surface) / 0.92); color: rgb(var(--ink));
  border: 1px solid rgb(var(--line));
  font-size: 0.8125rem; font-weight: 800;
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}

/* --- 4.21 Category tiles --------------------------------------------------
   Used on the homepage "Browse by category" grid. A more graphic variant of
   the plain .tpi-card for a section that is pure navigation (icon + label),
   not editorial content — larger icon plate, accent-tinted on hover, and an
   explicit "Browse →" affordance instead of relying on the whole tile being
   a click target to read as one. */
.tpi-catcard {
  display: flex; flex-direction: column; gap: 1rem;
  padding: 1.5rem 1.375rem;
  background-color: rgb(var(--surface));
  border: 1px solid rgb(var(--line)); border-radius: var(--radius);
  text-decoration: none;
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease, background-color .2s ease;
}
.tpi-catcard:hover {
  transform: translateY(-3px);
  border-color: rgb(var(--accent-fg) / 0.45);
  background-color: rgb(var(--accent-soft));
  box-shadow: 0 14px 30px -12px rgb(var(--shadow-color) / calc(var(--shadow-strength) * 2.2));
}
.tpi-catcard__icon {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 3.25rem; height: 3.25rem; border-radius: 0.875rem;
  background:
    radial-gradient(120% 120% at 20% 15%, rgb(var(--accent) / 0.22) 0%, transparent 60%),
    rgb(var(--accent-soft));
  color: rgb(var(--accent-fg));
}
.tpi-catcard__icon svg { width: 1.625rem; height: 1.625rem; }
.tpi-catcard__title { margin: 0; font-size: 1.0625rem; font-weight: 700; color: rgb(var(--ink)); letter-spacing: -0.015em; }
.tpi-catcard__dek { margin: 0.375rem 0 0; font-size: 0.875rem; line-height: 1.6; color: rgb(var(--muted)); flex: 1 1 auto; }
.tpi-catcard__cta {
  display: inline-flex; align-items: center; gap: 0.375rem;
  margin-top: 0.25rem; font-size: 0.8125rem; font-weight: 700; color: rgb(var(--accent-fg));
}
.tpi-catcard__cta svg { width: 0.9375rem; height: 0.9375rem; transition: transform .15s ease; }
.tpi-catcard:hover .tpi-catcard__cta svg { transform: translateX(3px); }

/* --- 4.22 Review spotlight --------------------------------------------------
   A single-item editorial feature for the homepage — one real, already-
   published review pulled out and given a larger, magazine-style treatment.
   Content (image, dek, facts, link) always comes from the linked article
   itself; nothing here is a fabricated rating or claim. */
.tpi-spotlight {
  display: grid; gap: 0;
  border: 1px solid rgb(var(--line)); border-radius: var(--radius-lg);
  background-color: rgb(var(--surface));
  overflow: hidden;
}
@media (min-width: 768px) { .tpi-spotlight { grid-template-columns: 1fr 1fr; align-items: stretch; } }
/* object-fit: contain (not cover) — this is a single product photo, not a
   scene, so cropping it to fill the box would cut off part of the product.
   Same treatment as .tpi-plate elsewhere on the site: plate background,
   contain, brightness-adjusted for dark mode. */
.tpi-spotlight__media { position: relative; aspect-ratio: 16 / 10; background-color: rgb(var(--plate)); min-height: 0; }
@media (min-width: 768px) { .tpi-spotlight__media { aspect-ratio: auto; } }
.tpi-spotlight__media img { width: 100%; height: 100%; object-fit: contain; display: block; padding: 1.5rem; filter: brightness(var(--plate-brightness)); }
.tpi-spotlight__body { padding: 1.75rem; display: flex; flex-direction: column; }
@media (min-width: 768px) { .tpi-spotlight__body { padding: 2.5rem; justify-content: center; } }
.tpi-spotlight__title { margin: 0.75rem 0 0.625rem; font-size: 1.375rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.25; color: rgb(var(--ink)); }
@media (min-width: 768px) { .tpi-spotlight__title { font-size: 1.625rem; } }
.tpi-spotlight__dek { margin: 0 0 1.25rem; font-size: 0.9375rem; line-height: 1.65; color: rgb(var(--body)); max-width: 46ch; }
.tpi-spotlight__facts {
  display: grid; grid-template-columns: 1fr; gap: 0.75rem;
  margin: 0 0 1.5rem; padding: 1rem 0; border-top: 1px solid rgb(var(--line)); border-bottom: 1px solid rgb(var(--line));
}
@media (min-width: 480px) { .tpi-spotlight__facts { grid-template-columns: repeat(3, 1fr); gap: 1rem; } }

/* ==========================================================================
   5. MOTION, FOCUS & PRINT
   ========================================================================== */

/* Visible keyboard focus everywhere, including inside prose. */
a:focus-visible, button:focus-visible, summary:focus-visible {
  outline: 2px solid rgb(var(--accent-fg));
  outline-offset: 2px; border-radius: 0.25rem;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; scroll-behavior: auto !important;
  }
  .tpi-card:hover { transform: none; }
  .tpi-progress { display: none; }
}

@media print {
  .tpi-header, .tpi-stickybar, .tpi-totop, .tpi-progress, .tpi-toc, .tpi-toc-mobile,
  .tpi-skip, .tpi-ftc, .tpi-byline, .tpi-badge, .tpi-footer { display: none !important; }
  body { background: #fff; color: #000; }

  /* The gear checklist is meant to leave the browser on paper. Drop the card
     chrome so the list itself is what prints, keep the drawn boxes tickable,
     and stop a row from being split across a page break. */
  article { border: 0 !important; box-shadow: none !important; padding: 0 !important; }
  .tpi-checklist li {
    background: #fff; border: 1px solid #999;
    break-inside: avoid; page-break-inside: avoid;
  }
  .tpi-checklist li svg { color: #000; }
  .tpi-verdict, .tpi-table-wrap, .tpi-faq details { break-inside: avoid; page-break-inside: avoid; }
  a[href]::after { content: ""; }
}
