@font-face{font-family:permanent;src:url(../media/ABCP3rman3nt_Book-s.p.19hudjq5qhka2.woff)format("woff");font-display:swap;font-weight:400;font-style:normal}@font-face{font-family:permanent Fallback;src:local(Arial);ascent-override:101.39%;descent-override:30.57%;line-gap-override:0.0%;size-adjust:103.37%}.permanent_8d51af83-module__n1ZD4W__className{font-family:permanent,permanent Fallback}.permanent_8d51af83-module__n1ZD4W__variable{--font-permanent:"permanent", "permanent Fallback"}
.archivo_d30d706d-module__8hpm2q__className{font-family:Archivo,Archivo Fallback;font-style:normal}.archivo_d30d706d-module__8hpm2q__variable{--font-archivo:"Archivo", "Archivo Fallback"}
.newsreader_debf26f0-module__LxEyYG__className{font-family:Newsreader,Newsreader Fallback}.newsreader_debf26f0-module__LxEyYG__variable{--font-newsreader:"Newsreader", "Newsreader Fallback"}
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:var(--font-permanent), "Helvetica Neue", Arial, sans-serif;--font-serif:var(--font-newsreader), Georgia, serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-xl:36rem;--container-3xl:48rem;--container-4xl:56rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--text-7xl:4.5rem;--text-7xl--line-height:1;--font-weight-light:300;--font-weight-normal:400;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-normal:0em;--leading-relaxed:1.625;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-paper:#fafafa;--color-panel:#e8e8e8;--color-panel-soft:#f1f1f1;--color-ink:#0a0a0a;--color-line:#dcdcdc;--color-mist:#6e6e6e;--color-accent:#fff500;--font-display:var(--font-archivo), "Helvetica Neue", Arial, sans-serif}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}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;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-2{top:calc(var(--spacing) * 2)}.top-4{top:calc(var(--spacing) * 4)}.right-4{right:calc(var(--spacing) * 4)}.bottom-4{bottom:calc(var(--spacing) * 4)}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-10{margin-top:calc(var(--spacing) * 10)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mt-14{margin-top:calc(var(--spacing) * 14)}.mt-16{margin-top:calc(var(--spacing) * 16)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mb-10{margin-bottom:calc(var(--spacing) * 10)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.table{display:table}.aspect-\[3\/4\]{aspect-ratio:3/4}.aspect-\[4\/3\]{aspect-ratio:4/3}.aspect-\[5\/4\]{aspect-ratio:5/4}.aspect-\[16\/9\]{aspect-ratio:16/9}.aspect-\[16\/10\]{aspect-ratio:16/10}.h-1{height:calc(var(--spacing) * 1)}.h-4{height:calc(var(--spacing) * 4)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-full{height:100%}.h-px{height:1px}.min-h-5{min-height:calc(var(--spacing) * 5)}.min-h-\[calc\(100svh-113px\)\]{min-height:calc(100svh - 113px)}.min-h-full{min-height:100%}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-12{width:calc(var(--spacing) * 12)}.w-16{width:calc(var(--spacing) * 16)}.w-fit{width:fit-content}.w-full{width:100%}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.max-w-xl{max-width:var(--container-xl)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-130{min-width:calc(var(--spacing) * 130)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.-translate-y-2{--tw-translate-y:calc(var(--spacing) * -2);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-0{--tw-translate-y:calc(var(--spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-2{--tw-translate-y:calc(var(--spacing) * 2);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-3{--tw-translate-y:calc(var(--spacing) * 3);translate:var(--tw-translate-x) var(--tw-translate-y)}.-rotate-45{rotate:-45deg}.rotate-45{rotate:45deg}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.scroll-mt-24{scroll-margin-top:calc(var(--spacing) * 24)}.scroll-mt-28{scroll-margin-top:calc(var(--spacing) * 28)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-7{gap:calc(var(--spacing) * 7)}.gap-8{gap:calc(var(--spacing) * 8)}.gap-10{gap:calc(var(--spacing) * 10)}.gap-12{gap:calc(var(--spacing) * 12)}.gap-16{gap:calc(var(--spacing) * 16)}.gap-24{gap:calc(var(--spacing) * 24)}.gap-28{gap:calc(var(--spacing) * 28)}.gap-x-16{column-gap:calc(var(--spacing) * 16)}.gap-y-12{row-gap:calc(var(--spacing) * 12)}.self-center{align-self:center}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.border{border-style:var(--tw-border-style);border-width:1px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-accent{border-color:var(--color-accent)}.border-ink{border-color:var(--color-ink)}.border-line{border-color:var(--color-line)}.border-paper\/40{border-color:#fafafa66}@supports (color:color-mix(in lab, red, red)){.border-paper\/40{border-color:color-mix(in oklab, var(--color-paper) 40%, transparent)}}.border-transparent{border-color:#0000}.bg-accent{background-color:var(--color-accent)}.bg-ink{background-color:var(--color-ink)}.bg-panel{background-color:var(--color-panel)}.bg-panel-soft{background-color:var(--color-panel-soft)}.bg-paper{background-color:var(--color-paper)}.bg-paper\/35{background-color:#fafafa59}@supports (color:color-mix(in lab, red, red)){.bg-paper\/35{background-color:color-mix(in oklab, var(--color-paper) 35%, transparent)}}.bg-paper\/80{background-color:#fafafacc}@supports (color:color-mix(in lab, red, red)){.bg-paper\/80{background-color:color-mix(in oklab, var(--color-paper) 80%, transparent)}}.bg-paper\/95{background-color:#fafafaf2}@supports (color:color-mix(in lab, red, red)){.bg-paper\/95{background-color:color-mix(in oklab, var(--color-paper) 95%, transparent)}}.bg-transparent{background-color:#0000}.bg-gradient-to-t{--tw-gradient-position:to top in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-paper\/85{--tw-gradient-from:#fafafad9}@supports (color:color-mix(in lab, red, red)){.from-paper\/85{--tw-gradient-from:color-mix(in oklab, var(--color-paper) 85%, transparent)}}.from-paper\/85{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.via-paper\/15{--tw-gradient-via:#fafafa26}@supports (color:color-mix(in lab, red, red)){.via-paper\/15{--tw-gradient-via:color-mix(in oklab, var(--color-paper) 15%, transparent)}}.via-paper\/15{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-paper\/10{--tw-gradient-to:#fafafa1a}@supports (color:color-mix(in lab, red, red)){.to-paper\/10{--tw-gradient-to:color-mix(in oklab, var(--color-paper) 10%, transparent)}}.to-paper\/10{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.object-cover{object-fit:cover}.object-\[42\%_center\]{object-position:42% center}.object-\[55\%_center\]{object-position:55% center}.p-10{padding:calc(var(--spacing) * 10)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-7{padding-inline:calc(var(--spacing) * 7)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-16{padding-block:calc(var(--spacing) * 16)}.py-20{padding-block:calc(var(--spacing) * 20)}.py-24{padding-block:calc(var(--spacing) * 24)}.py-28{padding-block:calc(var(--spacing) * 28)}.py-32{padding-block:calc(var(--spacing) * 32)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-8{padding-top:calc(var(--spacing) * 8)}.pt-12{padding-top:calc(var(--spacing) * 12)}.pt-14{padding-top:calc(var(--spacing) * 14)}.pt-16{padding-top:calc(var(--spacing) * 16)}.pt-28{padding-top:calc(var(--spacing) * 28)}.pr-6{padding-right:calc(var(--spacing) * 6)}.pb-1{padding-bottom:calc(var(--spacing) * 1)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-10{padding-bottom:calc(var(--spacing) * 10)}.pb-16{padding-bottom:calc(var(--spacing) * 16)}.pb-20{padding-bottom:calc(var(--spacing) * 20)}.pb-24{padding-bottom:calc(var(--spacing) * 24)}.pb-32{padding-bottom:calc(var(--spacing) * 32)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.text-center{text-align:center}.text-left{text-align:left}.align-top{vertical-align:top}.font-display{font-family:var(--font-display)}.font-sans{font-family:var(--font-sans)}.font-serif{font-family:var(--font-serif)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[30px\]{font-size:30px}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-9{--tw-leading:calc(var(--spacing) * 9);line-height:calc(var(--spacing) * 9)}.leading-\[1\.05\]{--tw-leading:1.05;line-height:1.05}.leading-\[1\.8\]{--tw-leading:1.8;line-height:1.8}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.1em\]{--tw-tracking:0px;letter-spacing:0px}.tracking-\[0\.2em\]{--tw-tracking:0px;letter-spacing:0px}.tracking-\[0\.3em\]{--tw-tracking:0px;letter-spacing:0px}.tracking-\[0\.25em\]{--tw-tracking:0px;letter-spacing:0px}.tracking-\[0\.28em\]{--tw-tracking:0px;letter-spacing:0px}.tracking-\[0\.35em\]{--tw-tracking:0px;letter-spacing:0px}.tracking-\[0\.45em\]{--tw-tracking:0px;letter-spacing:0px}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.text-ink{color:var(--color-ink)}.text-ink\/75{color:#0a0a0abf}@supports (color:color-mix(in lab, red, red)){.text-ink\/75{color:color-mix(in oklab, var(--color-ink) 75%, transparent)}}.text-ink\/50{color:#0a0a0a80}@supports (color:color-mix(in lab, red, red)){.text-ink\/50{color:color-mix(in oklab, var(--color-ink) 50%, transparent)}}.text-mist{color:var(--color-mist)}.text-paper{color:var(--color-paper)}.text-paper\/55{color:#fafafa8c}@supports (color:color-mix(in lab, red, red)){.text-paper\/55{color:color-mix(in oklab, var(--color-paper) 55%, transparent)}}.text-paper\/75{color:#fafafabf}@supports (color:color-mix(in lab, red, red)){.text-paper\/75{color:color-mix(in oklab, var(--color-paper) 75%, transparent)}}.lowercase{text-transform:lowercase}.normal-case{text-transform:none}.italic{font-style:italic}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-300{--tw-duration:.3s;transition-duration:.3s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.duration-1000{--tw-duration:1s;transition-duration:1s}.outline-none{--tw-outline-style:none;outline-style:none}@media (hover:hover){.group-hover\:translate-x-1:is(:where(.group):hover *){--tw-translate-x:calc(var(--spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.group-hover\:bg-accent:is(:where(.group):hover *){background-color:var(--color-accent)}}.placeholder\:text-mist\/60::placeholder{color:#8a8a8a99}@supports (color:color-mix(in lab, red, red)){.placeholder\:text-mist\/60::placeholder{color:color-mix(in oklab, var(--color-mist) 60%, transparent)}}.placeholder\:text-paper\/40::placeholder{color:#fafafa66}@supports (color:color-mix(in lab, red, red)){.placeholder\:text-paper\/40::placeholder{color:color-mix(in oklab, var(--color-paper) 40%, transparent)}}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-paper:hover{background-color:var(--color-paper)}.hover\:text-ink:hover{color:var(--color-ink)}.hover\:text-mist:hover{color:var(--color-mist)}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:border-ink:focus{border-color:var(--color-ink)}@media (min-width:40rem){.sm\:flex{display:flex}.sm\:hidden{display:none}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:object-center{object-position:center}}@media (min-width:48rem){.md\:block{display:block}.md\:hidden{display:none}.md\:aspect-\[16\/8\]{aspect-ratio:16/8}.md\:min-h-\[calc\(100svh-137px\)\]{min-height:calc(100svh - 137px)}.md\:w-1\/2{width:50%}.md\:w-2\/5{width:40%}.md\:w-3\/5{width:60%}.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\:grid-cols-\[1fr_0\.9fr\]{grid-template-columns:1fr .9fr}.md\:flex-row{flex-direction:row}.md\:flex-row-reverse{flex-direction:row-reverse}.md\:items-center{align-items:center}.md\:items-end{align-items:flex-end}.md\:justify-between{justify-content:space-between}.md\:gap-10{gap:calc(var(--spacing) * 10)}.md\:gap-16{gap:calc(var(--spacing) * 16)}.md\:gap-20{gap:calc(var(--spacing) * 20)}.md\:gap-24{gap:calc(var(--spacing) * 24)}.md\:gap-32{gap:calc(var(--spacing) * 32)}.md\:gap-36{gap:calc(var(--spacing) * 36)}.md\:object-center{object-position:center}.md\:px-10{padding-inline:calc(var(--spacing) * 10)}.md\:py-20{padding-block:calc(var(--spacing) * 20)}.md\:py-24{padding-block:calc(var(--spacing) * 24)}.md\:py-28{padding-block:calc(var(--spacing) * 28)}.md\:py-32{padding-block:calc(var(--spacing) * 32)}.md\:py-36{padding-block:calc(var(--spacing) * 36)}.md\:py-44{padding-block:calc(var(--spacing) * 44)}.md\:pt-36{padding-top:calc(var(--spacing) * 36)}.md\:pb-20{padding-bottom:calc(var(--spacing) * 20)}.md\:text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.md\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.md\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.md\:text-7xl{font-size:var(--text-7xl);line-height:var(--tw-leading,var(--text-7xl--line-height))}.md\:text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.md\:text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.md\:text-\[40px\]{font-size:40px}.md\:leading-\[48px\]{--tw-leading:48px;line-height:48px}}@media (min-width:64rem){.lg\:flex{display:flex}.lg\:w-1\/2{width:50%}.lg\:w-2\/5{width:40%}.lg\:w-3\/5{width:60%}}}html{scroll-behavior:smooth}body{background:var(--color-paper);color:var(--color-ink);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
/* Scrollbar hidden — Lenis already supplies the scroll feel, so the
   browser's own bar is just visual noise down the right edge. Scrolling
   itself is untouched; this only hides the track/thumb chrome. */
html{scrollbar-width:none;-ms-overflow-style:none}
html::-webkit-scrollbar{width:0;height:0;display:none}
::selection{background:var(--color-accent);color:var(--color-ink)}
/* Brand lockup — "essential / mind" stacked and centred, with the letter-spacing
   the design calls for. Declared unlayered so it wins over @layer utilities,
   whose compiled tracking-[...] utilities all collapse to letter-spacing:0. */
/* ---- Heading system -----------------------------------------------------
   ABC Permanent ships a single weight (Book 400) — there is no bold file, so
   every font-bold heading was FAUX bold, synthesised by smearing the regular
   weight. Dropping to 400 is what "regular instead of bold" means here, and
   it removes that distortion rather than merely lightening the type.

   Negative tracking goes to 0 for the same reason: hierarchy should come from
   size and space, not from squeezing and thickening the letterforms.

   Sizes step down per the brief — page titles by 1pt, primary headings by 2pt
   — expressed against the existing scale tokens so the responsive steps and
   the global type scale both still apply. Keyed on tag + size class because
   h1 and h2 share some of those classes at different levels.
   ------------------------------------------------------------------------ */
/* Design review (TYPOGRAFIE): headlines should get their presence from being
   lighter and more open rather than from weight. The weight half is the rule
   below — the family ships a single Book 400, so every `font-bold` here was a
   browser-synthesised faux bold, and dropping it is what "leichter" means in
   practice. This is the spacing half: a little positive tracking, scaled down
   as the headings get smaller, since what reads as airy at display size reads
   as gappy at 20px.

   The hero is deliberately excluded. Its size is solved against the viewport
   so the opening lines break where they should, and widening the letters
   re-breaks them. */
/* 4b: the page titles read as over-spaced at 0.07em — "a bit tooo much".
   Pulled back across the whole heading scale rather than on h1 alone: taking
   only the titles down would leave the section headings below them MORE open
   than the titles above, which inverts the hierarchy the tracking exists to
   create. The steps keep their relationship, just narrower. */
main h1:not(.hero-title) { letter-spacing: 0.04em }
main h2 { letter-spacing: 0.035em }
main h3 { letter-spacing: 0.025em }
main .hero-title { letter-spacing: 0 }

/* The small section labels ("core areas", "beyond essential mind", the 01/02/03
   markers, the form field labels) were authored with wide tracking, which
   compiles to 0px like every other arbitrary tracking value in this build. At
   this size the wide setting is the whole point of the label, so the authored
   values are restored by hand.

   Scoped to the labels rather than fixed globally: the same dead utilities are
   on the nav, the footer and the hero, and reviving those is a separate change
   with a much wider blast radius. CTA links are excluded — they carry the same
   class but are meant to read as a sentence, not as a label. */
main .text-xs.tracking-\[0\.2em\]:not(.link-mark) { letter-spacing: 0.2em }
main .text-xs.tracking-\[0\.25em\]:not(.link-mark) { letter-spacing: 0.25em }
main .text-xs.tracking-\[0\.45em\]:not(.link-mark) { letter-spacing: 0.45em }
main h1.font-bold, main h2.font-bold, main h3.font-bold { font-weight: 400 }

/* H1 — page title: 1pt down */
main h1.text-4xl { font-size: calc(var(--text-4xl) - 1pt) }
main h1.text-5xl { font-size: calc(var(--text-5xl) - 1pt) }
@media (min-width: 48rem) {
  main h1.md\:text-5xl { font-size: calc(var(--text-5xl) - 1pt) }
  main h1.md\:text-6xl { font-size: calc(var(--text-6xl) - 1pt) }
}

/* H2 / H3 — section headings: 2pt down */
main h2.text-xl,  main h3.text-xl  { font-size: calc(var(--text-xl)  - 2pt) }
main h2.text-2xl, main h3.text-2xl { font-size: calc(var(--text-2xl) - 2pt) }
main h2.text-3xl, main h3.text-3xl { font-size: calc(var(--text-3xl) - 4pt) }
main h2.text-4xl, main h3.text-4xl { font-size: calc(var(--text-4xl) - 6pt) }
@media (min-width: 48rem) {
  main h2.md\:text-2xl, main h3.md\:text-2xl { font-size: calc(var(--text-2xl) - 2pt) }
  main h2.md\:text-3xl, main h3.md\:text-3xl { font-size: calc(var(--text-3xl) - 4pt) }
  main h2.md\:text-4xl, main h3.md\:text-4xl { font-size: calc(var(--text-4xl) - 6pt) }
  main h2.md\:text-5xl { font-size: calc(var(--text-5xl) - 10pt) }
  main h2.md\:text-6xl { font-size: calc(var(--text-6xl) - 4pt) }
}

/* ---- The same system on mobile ------------------------------------------
   The burger menu's links and the sub-labels inside body copy were the last
   places still asking for a weight ABC Permanent does not have, so both were
   being synthesised. Neither needs it: the menu links are already the largest
   type on that screen, and the sub-labels sit in ink while the copy beneath
   them is mist — colour already separates them. Negative tracking goes with
   it, for the same reason it went from the headings. */
.site-mobile-nav nav a{font-weight:400;letter-spacing:0}
main p.font-semibold, main a.font-semibold{font-weight:400;letter-spacing:0}

/* ---- Accent rule -------------------------------------------------------
   The yellow mark that sits above a page title. One token for all of them:
   it was 4px tall and, in one place, 48px wide instead of 64 — so the
   proportion drifted.

   Height is matched to the active nav item's yellow block (14px type plus its
   padding = 22px), so the two uses of the accent read as one shape: the rule
   above a page title and the marker behind the current menu item are the same
   64x22 mark. If the nav type size changes, bring this with it. */
:root{ --accent-mark-h: 22px }
.accent-rule{width:4rem;height:var(--accent-mark-h);background:var(--color-accent)}

/* ---- Dividers removed ---------------------------------------------------
   Every grey hairline on the site — 68 of them: section rules, the header
   edge, the footer rule, the separators between list items — came from one
   colour class. Neutralising that class removes them all without editing 72
   places in the markup, and putting them back is a single line.

   Form fields are the deliberate exception. Their bottom border is not
   decoration: it is the only thing that makes an empty input visible, so
   without it the booking form would be a set of invisible boxes. */
.border-line{border-color:transparent}
/* The header has its own, more specific rule further down setting a 70%
   version of the line colour, so the class alone does not reach it. */
header.border-line{border-color:transparent}
input.border-line,textarea.border-line,select.border-line{border-color:var(--color-line)}

/* ---- Page width ---------------------------------------------------------
   The outer container was 72rem, which left large screens with a narrow band
   of content and a lot of empty margin. Widening the token moves that space
   inside the composition instead: the 48 places using max-w-6xl all follow,
   and no HTML changes.

   Deliberately only the OUTER container grows. The text columns are capped
   separately (max-w-xl, 36rem) and are left alone, so line length — and with
   it readability — is unchanged. The page gets wider; the words do not.

   84rem was still only ~70% of a 1920 screen, which read as a narrow column
   floating in empty margin. The cap is gone: the outer container now takes
   the full width and the page's own gutter is the only margin. To put a
   ceiling back — e.g. for very wide monitors — set this to a length such as
   110rem and everything follows. */
:root{ --container-6xl: 100% }

/* The gutter was sized for a capped column. Once the container runs the whole
   width it has to grow with the screen, or the content ends up hard against
   the glass. */
@media (min-width: 90rem) {
  .max-w-6xl { padding-inline: 4rem }
}

@media (min-width: 120rem) {
  .max-w-6xl { padding-inline: 6rem }
}

/* ---- Header hierarchy ---------------------------------------------------
   The wordmark steps back a little and the navigation comes forward, so the
   menu reads at a glance without the header getting louder overall. Set here
   rather than on the 20 header markups, so the balance stays in one place:
   logo 40->34px (26 on small screens), nav 11->14px. */
header .brand-lockup{font-size:17px}
@media (min-width:48rem){header .brand-lockup{font-size:21px}}
header nav .nav-mark,
header nav a[href$="booking.html"]{font-size:15.3px}

.brand-lockup{display:block;font-family:var(--font-sans);font-weight:400;text-align:center;text-transform:lowercase;letter-spacing:.1em;line-height:1.2}
/* iOS draws its own start-playback overlay on any <video> that is not
   playing, on top of the poster. That is separate from the site's own
   scripting and appears whenever autoplay is declined — which is the normal
   case on a phone. Both videos here are decorative backgrounds behind the
   hero, so the poster frame is the intended fallback and the control is
   just stray UI over the artwork. */
/* The language gate can no longer be scrolled past, so on a phone these two
   buttons are the only way into the site — and they render at 17x18px, well
   under the ~44px a fingertip needs. This gives each one a finger-sized hit
   area without changing how it looks: the pseudo-element is invisible and
   out of flow, so nothing moves. Width stops at 32px because the two centres
   are only 34px apart — a full 44px would overlap and send taps meant for EN
   to DE. Touch pointers only; a mouse is precise enough already. */
@media (pointer:coarse){
  .lang-prompt-option{position:relative}
  .lang-prompt-option::after{content:"";position:absolute;left:50%;top:50%;
    width:32px;height:44px;transform:translate(-50%,-50%)}
}

video::-webkit-media-controls-start-playback-button{display:none!important;-webkit-appearance:none}
video::-webkit-media-controls{display:none!important}
video::-webkit-media-controls-panel{display:none!important;-webkit-appearance:none}

/* ---- Capitalisation ----------------------------------------------------
   The all-lowercase display style is an English typographic treatment. German
   orthography capitalises every noun, so forcing it there produces incorrect
   spelling ("kernbereiche", "unsere praxis"). On the German version the
   dictionary's own capitalisation is therefore what reaches the page, and the
   lowercase transform is switched off. site.js sets <html lang="de"> when
   German is active, so this follows the language automatically. */
html[lang="de"] .lowercase{text-transform:none}

/* ---- Global type scale -------------------------------------------------
   Two knobs for the overall size of the type. 1 = the original scale; lower
   means smaller text and more white space. Display sizes take the larger
   reduction, because that is where the heaviness is felt; body copy takes a
   gentler one so it stays comfortable to read.
   --text-xs and --text-sm are deliberately NOT scaled: they carry the main
   navigation, the footer navigation, the small labels and the footer logo,
   none of which should shrink. The mobile menu is pinned just below for the
   same reason. Line heights are unitless ratios in this build, so they follow
   the font size automatically and need no adjustment here. */
:root{
  --type-display:.78;
  --type-body:.94;
  --text-base:calc(1rem * var(--type-body));
  --text-lg:calc(1.125rem * var(--type-body));
  --text-xl:calc(1.25rem * var(--type-body));
  --text-2xl:calc(1.5rem * var(--type-display));
  --text-3xl:calc(1.875rem * var(--type-display));
  --text-4xl:calc(2.25rem * var(--type-display));
  --text-5xl:calc(3rem * var(--type-display));
  --text-6xl:calc(3.75rem * var(--type-display));
  --text-7xl:calc(4.5rem * var(--type-display));
}
/* The mobile menu is the main navigation on small screens: original size. */
.site-mobile-nav nav a{font-size:1.875rem}
/* Hero splash type — the headline and both slogan lines share one colour, so the
   whole block reads as a single unit. The transparency lives in the colour rather
   than in `opacity`, because .hero-title and .hero-banner animate the opacity
   property during the intro; setting it here would fight that animation.
   Headline sizes are the former text-5xl / text-7xl, 20% smaller. */
.hero-stage{text-align:center;--hero-size:1rem}
.hero-stage .hero-title{margin-inline:auto}
/* One base size drives the whole hero: the two statements sit at it and the
   headline 10% above, so the three stay locked in proportion at every width
   — changing --hero-size moves all of them together. Regular weight
   throughout, overriding the font-bold utility still on the h1. */
.hero-stage .hero-title,.hero-stage .hero-banner p{color:rgba(255,255,255,.75);font-weight:400}
.hero-stage .hero-banner p{font-size:var(--hero-size)}
.hero-stage .hero-title{font-size:calc(var(--hero-size) * 1.1)}
/* Below the md breakpoint each line has to hold to one line, as on desktop.
   At 16px the longest needs 390px and a 375px phone offers 327, so the size
   is derived from the space available rather than fixed: a line's width is
   ~25x its font size, so dividing the usable width by 25 is the largest size
   that still fits — ~13px on a 375px screen, ~11px on a 320px one. Capped at
   16px so it never exceeds the desktop size, with a floor so it cannot become
   unreadable. 3rem is the section's px-6 padding on both sides. */
@media (max-width:47.99rem){
  .hero-stage{--hero-size:clamp(10px,calc((100vw - 3rem) / 25),16px)}
}
/* Client, 2026-10-29, with a phone shot of the old essential-mind.com entry
   screen: "match the entry font size to this one — the 'live what matters'."
   That reference line measures 12px; ours came out at 14.39px on a 375px
   phone, so the base size takes the same 0.834 step and the divisor goes
   from 25 to 30. The headline lands at 11.99px there and the two slogan
   lines come down with it, because one base size drives all three and a
   headline left smaller than its own sub-lines would read as a mistake.
   Phone only — desktop keeps the 1rem base. */
@media (max-width:47.99rem){
  .hero-stage{--hero-size:clamp(8.34px,calc((100vw - 3rem) / 30),13.34px)}
}
/* While the splash fills the screen the headline sits in the middle of the
   video. The same container later becomes the 22rem banner, where the (still
   laid-out but invisible) headline would push the slogans off-centre — so the
   centring is scoped to the pre-morph state and the banner keeps its original
   bottom alignment. */
body.has-splash:not(.has-morphed) .splash-content{align-items:center;padding-bottom:0}
.mark{-webkit-box-decoration-break:clone;box-decoration-break:clone;border-radius:.6em .3em .55em .25em/.4em .7em .3em .6em;margin-inline:-.22em;padding:.08em .22em;transition:background-color .3s}.link-mark{background-image:linear-gradient(to top, var(--color-accent), var(--color-accent));background-position:0 100%;background-repeat:no-repeat;background-size:100% .22em;border-radius:.25em .15em .3em .1em/.2em .3em .1em .25em;margin-inline:-.2em;padding:.12em .2em;transition:background-size .35s}.link-mark:hover,.group:hover .link-mark{background-size:100% 100%}.nav-mark{background-image:linear-gradient(to top, var(--color-accent), var(--color-accent));background-position:0 100%;background-repeat:no-repeat;background-size:0 .22em;padding-block:.12em;transition:background-size .35s,color .3s}.nav-mark-active{background-size:100% .22em}.reveal{opacity:0;transition:opacity .9s,transform .9s;transform:translateY(14px)}.reveal.is-visible{opacity:1;transform:translateY(0)}@media (prefers-reduced-motion:reduce){.reveal{opacity:1;transition:none;transform:none}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}

/* ===============================================================
   Splash intro — home page only.

   The film fills the viewport with no chrome over it. As you scroll
   the first screen, the header's background washes in, the titles
   rise and fade, and the footage pushes in fractionally while a
   paper-coloured veil deepens over it — so the page emerges out of
   the film rather than cutting to it.

   Driven by two custom properties set on <body> by initSplash():
     --splash-progress  0 → 1 across the first viewport
     --splash-chrome    0 → 1 slightly faster, for the header

   To remove the splash entirely, delete `has-splash` from <body>
   on index.html. Nothing else needs changing.
   =============================================================== */

/* The whole bar — logo included — is absent over the film, then arrives as
   one piece. `splash-lifted` is added by initSplash() once you have scrolled
   off the top, so the invisible bar cannot swallow clicks meant for the film. */
body.has-splash header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background-color: transparent;
  opacity: var(--splash-chrome, 0);
  pointer-events: none;
}

body.has-splash.splash-lifted header {
  pointer-events: auto;
}

/* The bar's paper background is its own layer. A calc() inside an alpha
   channel is invalid at computed-value time here and silently drops the
   whole declaration; a calc() in `opacity` is reliable. */
body.has-splash header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: var(--color-paper);
  opacity: 0.95;
}

body.has-splash #home {
  height: 100svh;
  height: var(--hero-vh, 100svh);
  min-height: 100svh;
  min-height: var(--hero-vh, 100svh);
}

/* the footage: a slow, barely perceptible push in */
body.has-splash .splash-media {
  transform: scale(calc(1 + var(--splash-progress, 0) * 0.06));
  transform-origin: 50% 45%;
  will-change: transform;
}

/* paper wash that deepens as the film hands over to the page */
body.has-splash #home::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-color: var(--color-paper);
  opacity: calc(var(--splash-progress, 0) * 0.6);
}

/* titles and the begin cue rise out of frame */
body.has-splash .splash-content {
  position: relative;
  z-index: 2;
  opacity: calc(1 - var(--splash-progress, 0) * 1.35);
  transform: translateY(calc(var(--splash-progress, 0) * -2.5rem));
  will-change: transform, opacity;
}

@media (prefers-reduced-motion: reduce) {
  /* initSplash() never runs here, so --splash-chrome stays 0 — the bar has to
     be made visible explicitly or it would never appear at all. */
  body.has-splash header {
    position: sticky;
    opacity: 1;
    pointer-events: auto;
  }
  body.has-splash .splash-media,
  body.has-splash .splash-content {
    transform: none;
    opacity: 1;
  }
  body.has-splash #home::after { opacity: 0; }
}

/* A soft, permanent fade at the foot of the hero — replaces the hard
   line that used to sit between the film and the vision statement.
   Runs the full 4cm regardless of splash/banner state or scroll. */
#home::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 4cm;
  background: linear-gradient(to bottom, transparent, var(--color-paper));
  pointer-events: none;
  z-index: 1;
}

/* ===============================================================
   Typeline — the vision quote types itself out as you scroll,
   finishing on a flashing dash.

   Every character always occupies its space; untyped ones are just
   `color: transparent`. Nothing reflows as it types, which keeps
   the effect calm and stops the block jumping around mid-scroll.

   The dash rides on the last typed character as a ::after, so it
   follows the write head across line breaks for free. It needs its
   own colour because the character carrying it may still be
   transparent.
   =============================================================== */

.typeline-char {
  color: transparent;
  transition: color 0.18s linear;
}

.typeline-char.is-typed {
  color: inherit;
}

.typeline-char.is-cursor {
  position: relative;
}

/* Drawn as a box rather than a glyph, so the caret is a true vertical rule
   at a predictable weight instead of whatever the serif's pipe looks like.
   Sized in em so it tracks the responsive type scale. */
.typeline-char.is-cursor::after {
  content: "";
  position: absolute;
  left: 100%;
  top: 0.14em;
  width: 0.05em;
  height: 0.92em;
  margin-left: 0.08em;
  background-color: var(--color-ink);
  pointer-events: none;
}

/* The caret is steady while the line is being written, the way a caret
   actually behaves mid-keystroke. `is-done` is added when the clause
   finishes: it flashes three times and then stays gone, because
   `forwards` holds the final keyframe, which is opacity 0. */
.typeline-char.is-cursor.is-done::after {
  animation: typeline-blink 1.1s steps(1, end) 3 forwards;
}

@keyframes typeline-blink {
  0%, 50% { opacity: 1; }
  50.01%, 100% { opacity: 0; }
}

/* No typing, no blinking — just the quote. */
@media (prefers-reduced-motion: reduce) {
  .typeline-char { color: inherit; transition: none; }
  .typeline-char.is-cursor::after { display: none; }
}

/* ===============================================================
   Link marking — quiet rule instead of yellow highlighter.

   The original marked links with a yellow bar that swelled to fill
   the whole word on hover. These rules replace that with a hairline
   in the text's own colour, thickening slightly on hover.

   Kept as an underline rather than removed outright so links are
   still identifiable as links; delete the `background-*` lines to
   strip them bare.
   =============================================================== */

.link-mark {
  /* Design review (LINKS / CTAS): at rest these carried nothing at all — the
     rule only wiped in on hover, so a link was indistinguishable from body
     copy until pointed at, and on a touch screen never announced itself at
     all. It now has a real underline at rest, which also means the link does
     not depend on colour to be recognisable. */
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.28em;
  text-decoration-color: currentColor;
  /* The yellow is kept, but promoted from "the only signal" to the hover
     flourish. It is the shared marking, not a full highlight — see the
     colour-accent block below for the band itself. */
  background-image: linear-gradient(to top, var(--color-accent), var(--color-accent));
  background-position: 0 calc(100% - var(--mark-lift));
  background-repeat: no-repeat;
  background-size: 0 var(--mark-band);
  border-radius: 0;
  margin-inline: 0;
  padding: 0 0 0.02em;
  transition: background-size 0.35s;
  /* "read the notes" is a stretched flex child, so its box ran the full
     width of the row and took the rule with it. Constraining the width keeps
     the rule on the words; it is a no-op for the inline links. */
  width: fit-content;
}

/* nothing at rest; the rule wipes in from the left on hover */
/* Touch screens have no pointer to take away, so :hover sticks to whatever
   was last tapped — the client saw an article title left permanently marked
   on a phone. Tailwind guards its own hover utilities this way; these
   hand-written ones were not, which is the whole of the bug. */
@media (hover: hover) {
.link-mark:hover,
.group:hover .link-mark {
  background-size: 100% var(--mark-band);
}
}

/* The trailing arrow, the second half of the review note. Done as a ::after so
   no markup carries it and the German copy inherits it without a single key
   being touched. `display:inline-block` is load-bearing: text decoration does
   not propagate into an atomic inline box, which is what keeps the underline
   on the words and off the arrow, as drawn in the mockup.

   Mail and phone links are excluded — an arrow reads as "go somewhere", which
   is wrong for an address you are meant to read or copy. */
.link-mark:not([href^="mailto:"]):not([href^="tel:"])::after {
  content: "\2192";
  display: inline-block;
  margin-left: 0.55em;
  transition: transform 0.3s;
}

@media (hover: hover) {
.link-mark:hover::after,
.group:hover .link-mark::after {
  transform: translateX(0.2em);
}
}

/* The CTA links read at body size, by the same tokens the body paragraphs
   use rather than a fixed pixel value, so they follow the type scale if it is
   ever retuned. They were 13px, which sat between the body copy and the small
   labels and read as a size of its own. */
.link-mark.text-xs { font-size: var(--text-sm) }

@media (min-width: 48rem) {
  .link-mark.text-xs { font-size: var(--text-base) }
}

.nav-mark {
  background-image: linear-gradient(to top, var(--color-accent), var(--color-accent));
  background-position: 0 calc(100% - var(--mark-lift));
  background-size: 0 var(--mark-band);
}

/* The section you are on is marked with the accent itself rather than a
   hairline under it: a far stronger cue at a glance, and the one place the
   yellow earns a functional job instead of being decoration. The negative
   margin matched by padding lets the block breathe around the word without
   shifting any neighbour, and background-size is already transitioned on
   .nav-mark, so it wipes in rather than snapping. */
/* Pabla 02, Active State: "Instead of the current thin underline, a subtle
   yellow background behind the active menu item creates a stronger visual cue
   while introducing the yellow accent in a functional way."

   So the current page is the one place that does NOT use the offset marking —
   it gets a filled field instead. The marking stays everywhere else it was
   introduced: link hovers, article-title hovers, the 01/02/03 markers and the
   notes call to action. The gradient the band is drawn with has to be turned
   off here, or it would paint over the fill. */
.nav-mark-active {
  background-image: none;
  background-color: var(--color-accent);
  color: var(--color-ink);
  /* Client, 2026-10-11: the field read as a button rather than a marking —
     it stood ~7px clear of the word on each side and 8px top and bottom.
     Pulled in to a marker-pen fit: the yellow now covers the font's own
     inline box and barely more, so it reads as a highlight over the word
     instead of a tab behind it. The negative margin still matches the
     padding, so nothing in the row moves. */
  margin-inline: -0.12em;
  padding: 0 0.12em;
}

/* ===============================================================
   One typeface — ABC Permanent Book everywhere.

   Body copy already used it. These two tokens are what still
   pointed elsewhere: headlines at Archivo, quotes and article
   copy at Newsreader. Repointing the tokens catches every
   `font-display` and `font-serif` utility across all 8 pages
   without touching a single HTML file.

   To go back, delete this block.
   =============================================================== */

:root {
  --font-display: var(--font-permanent), "Helvetica Neue", Arial, sans-serif;
  --font-serif: var(--font-permanent), "Helvetica Neue", Arial, sans-serif;
}

/* ===============================================================
   Crop the black edge off the studio footage.

   Both hero.webm and its poster carry three near-black rows at the
   bottom of the 1920x1080 frame — 0.28% of the height, baked into
   the source. At the desktop 16/8 aspect, object-cover already
   trims 5.5% off each edge and the band never shows. At the 5/4
   aspect used below `md`, the full frame height is visible and the
   band appears as a dark line.

   Nudging the media 1.2% larger from its top edge pushes the bottom
   out past the container's overflow: hidden — enough to clear the
   band at every aspect, small enough to cost nothing at the top or
   sides. Applies to the poster and the video together so they stay
   in register while the video loads.
   =============================================================== */

.crop-bottom > img,
.crop-bottom > video {
  transform: scale(1.012);
  transform-origin: center top;
}

/* ===============================================================
   Language switcher — EN | DE

   Deliberately quiet: sits a step smaller and lighter than the nav
   links so it reads as a utility rather than a fifth nav item. The
   inactive language is mist and lifts to ink on hover; the active
   one is already ink.

   Styled entirely here rather than with Tailwind utilities, because
   the compiled class list is fixed and these sizes do not exist in
   it. Purely presentational so far — see initLangSwitch() in
   site.js for the placeholder behaviour.
   =============================================================== */

.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  margin-left: 1.5rem;
  font-size: 12px;
  letter-spacing: 0;
  line-height: 1;
}

.lang-option {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  color: var(--color-mist);
  cursor: pointer;
  transition: color 0.3s;
}

@media (hover: hover) {
.lang-option:hover,
.lang-option:focus-visible {
  color: var(--color-ink);
}
}

.lang-option.is-active {
  color: var(--color-ink);
}

.lang-sep {
  color: var(--color-line);
  user-select: none;
}

/* In the mobile menu it sits above the email line, matching its inset. */
.lang-switch-mobile {
  margin-left: 0;
  padding: 0 2rem 1.25rem;
}

/* ===============================================================
   Language prompt — the pop-up that releases the splash.

   Appears once the three hero lines have finished fading in (see
   initLanguageGate() in site.js). Choosing EN or DE sets the site's
   language and, in the same action, unlocks and scrolls the page —
   there is no separate "begin" step any more.

   No box: plain text sitting top-right of the film. The header's nav is
   still invisible while the gate is shut, so that corner is free.
   =============================================================== */

.lang-prompt {
  position: absolute;
  right: 1.5rem;
  top: 1.5rem;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-size: 12px;
  letter-spacing: 0;
  opacity: 0;
  pointer-events: none;
  transform: translateY(6px);
  transition: opacity 700ms var(--morph-ease), transform 700ms var(--morph-ease);
}

@media (min-width: 768px) {
  .lang-prompt {
    right: 2.5rem;
    top: 2rem;
  }
}

.lang-prompt.is-shown {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

.lang-prompt-option {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  color: var(--color-ink);
  cursor: pointer;
  transition: color 0.3s;
}

@media (hover: hover) {
.lang-prompt-option:hover,
.lang-prompt-option:focus-visible {
  color: var(--color-mist);
}
}

.lang-prompt-sep {
  color: var(--color-mist);
  user-select: none;
}

@media (prefers-reduced-motion: reduce) {
  .lang-prompt {
    transition: none;
  }
}

/* While the gate is shut the page cannot be scrolled. Applied by JS,
   never by CSS alone, so that a visitor with JavaScript disabled is
   never trapped on the first screen. */
html.is-gated,
html.is-gated body {
  overflow: hidden;
}

/* The line under the header is gone with the rest of the grey rules. This is
   the rule that actually decides it — the generic `header.border-line` higher
   up the file has the same specificity and loses on order, so the colour has
   to be set here. Restore the two commented lines to bring the hairline back. */
header.border-line {
  border-color: transparent;
  /* border-color: #dcdcdcb3; */
  /* border-color: color-mix(in oklab, var(--color-line) 70%, transparent); */
}

/* ===============================================================
   Nav — quieter.

   The boxed "booking" button was the loudest thing in the header and
   fought the letterspaced links either side of it. Dropping the box
   leaves booking distinguished by weight of colour alone: ink where
   the others are mist. Everything steps down a size, and the language
   switcher steps down again so the hierarchy still reads.
   =============================================================== */

header nav a {
  /* Pabla 02, Visual Hierarchy: "a slightly smaller logo combined with larger,
     more legible menu items. This gives the navigation more presence while
     keeping the overall appearance minimal and understated." */
  /* 17px read as too big to the client. 10% off keeps the balance shift Pabla
     02 asked for — the menu is still clearly larger than the 14px it started
     at — without the extra weight. Reverting all the way to 14px would undo
     the designer's note entirely. */
  font-size: 15.3px;
  letter-spacing: 0;
}

/* booking's black square: ink border at rest, inverts to a solid
   black fill with white text on hover, and flashes accent yellow
   for the moment the mouse button is actually down. */
header nav a.border-ink {
  padding: 0.4em 0.9em;
  transition: background-color 0.3s, color 0.3s, border-color 0.3s;
}

/* Client, 2026-10-11: on the booking page itself the button showed no
   "you are here" at all — every other page marks its nav item, booking was
   the one gap. It cannot take the yellow field the others use, because the
   field would fight the button's own border, so it holds the ink inversion
   instead. This went yellow on 2026-10-13 and back to ink on 2026-10-17, the
   client settling on black held with yellow on hover — matching the section's
   own "request initial consultation" button, which is black and goes yellow
   under the pointer. Held and hover are a matched pair: swapping one without
   the other leaves the button unable to answer the mouse.

   Deliberately placed above the :hover and :active rules. All three have the
   same specificity, so the later ones still win while the pointer is over the
   button — the control keeps reacting to the mouse instead of going dead. */
header nav a.border-ink.nav-cta-active {
  background-color: var(--color-ink);
  border-color: var(--color-ink);
  color: var(--color-paper);
}

/* While the button is held black, hovering it goes yellow, exactly as the
   "request initial consultation" button does (bg-ink → hover:bg-accent
   hover:text-ink). The ordinary hover from the bordered rest state, white on
   black, is untouched: this only fires when .nav-cta-active is present.

   Three classes plus the pseudo-class, so it outranks the plain :hover rule
   below wherever it sits in the file. The border follows the fill, as it
   already does on :active — a leftover outline in the other colour reads as a
   mistake. */
@media (hover: hover) {
header nav a.border-ink.nav-cta-active:hover {
  background-color: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-ink);
}
}

@media (hover: hover) {
header nav a.border-ink:hover {
  background-color: var(--color-ink);
  color: var(--color-paper);
}
}

header nav a.border-ink:active {
  background-color: var(--color-accent);
  border-color: var(--color-accent);
  color: var(--color-ink);
}

.lang-switch {
  margin-left: 1.25rem;
  /* Was 8.1px — small enough that legibility suffered, which the design
     review called out. This rule is the one that wins; an earlier
     .lang-switch block sets a size too, and it is overridden here. */
  font-size: 12px;
  letter-spacing: 0;
}

/* ===============================================================
   Hero morph — one continuous motion from splash to landing page.

   FEATURE FLAG: `morph-intro` on <body> in index.html.
   Remove that one class and the page reverts to the previous
   behaviour (gate releases, page scrolls) with nothing else changed.

   What moves, all on the same clock:
     · the film shrinks from 100svh to its landing height, dropping
       below the header rather than under it
     · the header arrives
     · "live what matters." leaves as "grounded in science…" arrives
     · the language prompt retires once a choice is made
     · the rest of the site fades up

   Nothing here is a page change — the same <section id="home"> and
   the same <video> element resize in place, so the footage never
   cuts or reloads.

   TIMING — 1400ms on cubic-bezier(.22,1,.36,1). That curve moves
   decisively at the start and then takes a long time to settle,
   with no overshoot or bounce. Deliberately slower than a typical
   UI transition: this is a mental-health practice, and the intro
   should feel like a room opening rather than a slide changing.
   Both values are variables — tune them here, everything follows.
   =============================================================== */

:root {
  --morph-duration: 5600ms;
  --morph-ease: cubic-bezier(0.22, 1, 0.36, 1);
  /* The film fades while the page descends. Shorter than the 3000ms
     descent so the last stretch is already onto clean white. */
  --dissolve-duration: 2000ms;
  --header-h: 113px; /* measured and overwritten by initLanguageGate() */
}

/* Before a language is chosen the film stays exactly as it is — full
   bleed, edge to edge. Choosing one shrinks it down to a fixed-height
   banner permanently: no scroll required, and it never reverts. */
body.morph-intro #home {
  height: 100svh;
  height: var(--hero-vh, 100svh);
  margin-top: 0;
  transition: height var(--morph-duration) var(--morph-ease);
}

body.morph-intro.has-morphed #home {
  height: 22rem;
  min-height: 22rem;
}

/* the two lines cross-fade: the headline leaves first, the banner
   text arrives once it is out of the way, so they never overlap */
.hero-title {
  transition: opacity var(--morph-duration) var(--morph-ease), transform var(--morph-duration) var(--morph-ease);
}

body.morph-intro.has-morphed .hero-title {
  opacity: 0;
  transform: translateY(-10px);
  pointer-events: none;
}

.hero-banner {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--morph-duration) var(--morph-ease), transform var(--morph-duration) var(--morph-ease);
}

body.morph-intro.has-morphed .hero-banner {
  opacity: 1;
  transform: translateY(0);
}

/* Once morphed, the banner is a plain permanent fixture: the header
   is on immediately rather than waiting for scroll, and the film no
   longer reacts to scroll position at all (no paper wash, no push-in,
   no fading titles) — it just sits there being a banner. */
body.morph-intro.has-morphed header {
  opacity: 1;
  pointer-events: auto;
}

body.morph-intro.has-morphed #home::after {
  opacity: 0;
}

body.morph-intro.has-morphed .splash-content {
  opacity: 1;
  transform: none;
}

body.morph-intro.has-morphed .splash-media {
  transform: none;
}

/* Reduced motion: no morph, no cross-fade — the landing state simply
   is the state, reached without movement. */
@media (prefers-reduced-motion: reduce) {
  body.morph-intro #home,
  body.morph-intro .hero-title,
  body.morph-intro .hero-banner,
  body.morph-intro header,
  body.morph-intro main > div > *:not(#home),
  body.morph-intro footer {
    transition: none;
  }
}

/* ===============================================================
   Yellow hovers — quick in, slow out.

   Everything that turns accent-yellow on hover (request initial
   consultation, send request, join the notes, the six service links,
   the expert names) arrives at its normal 300ms but takes 1200ms —
   four times as long — to fall back to ink. The colour drains rather
   than snapping off.

   The technique: the transition declared on the resting state governs
   LEAVING the hover; the one declared inside :hover governs entering
   it. Two durations, one property.

   The nav's booking link is excluded — its yellow fill was removed
   when the box came off, so it has nothing to fade.
   =============================================================== */

.hover\:bg-accent {
  transition-property: background-color, color, border-color;
  transition-duration: 1200ms;
  transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
}

@media (hover: hover) {
.hover\:bg-accent:hover {
  transition-duration: 300ms;
}
}

/* nav booking carries the class but no longer fills yellow */
header nav a.hover\:bg-accent,
@media (hover: hover) {
header nav a.hover\:bg-accent:hover {
  transition-duration: 300ms;
}
}

/* ===============================================================
   Practice description — the third line of the hero.

   Sits under the brand description, a clear step down from it:
   smaller, tighter tracking, mist rather than ink. The hierarchy
   from top to bottom is therefore

     hero statement      "live what matters."          large, display
     brand description   "grounded in science…"        12px, ink/75
     practice descr.     "Mental health for…"          10px, mist

   Set in the copy's own casing rather than forced lowercase like
   the two lines above it — see the note in the README.
   =============================================================== */

.hero-practice {
  font-size: 10px;
  letter-spacing: 0;
  line-height: 1.5;
}

@media (min-width: 768px) {
  .hero-practice { font-size: 11px; }
}

/* It belongs to the brand description, so it arrives with it rather
   than on its own beat. */


@media (prefers-reduced-motion: reduce) {
  body.morph-intro .hero-practice { opacity: 1; transition: none; }
}



/* ===============================================================
   Hero lines — fade in one by one.

   Independent of the reveal/splash machinery: these three lines are
   the first thing on the page, so they animate on load rather than
   waiting on scroll or on begin. Each carries its own delay inline
   (600 / 1500 / 2400ms) via `transition-delay`, reusing the same
   staggering pattern as the rest of the site.
   =============================================================== */

.hero-line {
  opacity: 0;
  transition: opacity 1.1s var(--morph-ease, ease);
}

.hero-line.is-visible {
  opacity: 1;
}

/* the splash now carries only "live what matters." — a slower,
   more deliberate fade than the other hero-lines get, since it is
   the only thing arriving. A pure opacity fade, in place — no rise,
   no drift, just materializing where it already sits. */
.hero-line-slow {
  transition-duration: 6s;
}

@media (prefers-reduced-motion: reduce) {
  .hero-line {
    opacity: 1;
    transition: none;
  }
}

/* ===============================================================
   Notes popup — a quiet nudge toward the newsletter.

   Appears once, 30s after the page opens (see initNotesPopup() in
   site.js), sitting in its own corner rather than over the page —
   everything underneath stays fully usable, nothing is dimmed or
   blocked. Closing it (the ×, "not now", or Escape) is remembered
   for the rest of the session. Choosing "join the notes" does not
   duplicate the form here — it scrolls down to the real one and
   focuses its email field.

   Only present on pages that actually have a #notes section to
   scroll to; initNotesPopup() no-ops everywhere else.
   =============================================================== */

.notes-popup {
  position: fixed;
  left: 1.5rem;
  right: 1.5rem;
  bottom: 1.5rem;
  z-index: 40;
  display: flex;
  justify-content: center;
  pointer-events: none;
}

@media (min-width: 640px) {
  .notes-popup {
    left: auto;
    justify-content: flex-end;
  }
}

.notes-popup-card {
  position: relative;
  width: 100%;
  max-width: 22rem;
  padding: 1.5rem 2.25rem 1.5rem 1.5rem;
  background: #fafafad9;
  background: color-mix(in oklab, var(--color-paper) 85%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  /* Was a 1px grey border. The card still needs to separate itself from the
     page behind it, so the edge became a soft shadow instead of a rule. */
  border: 1px solid transparent;
  box-shadow: 0 2px 28px rgba(10, 10, 10, 0.1);
  opacity: 0;
  transform: translateY(0.75rem);
  transition: opacity 600ms ease, transform 600ms ease;
  pointer-events: none;
}

.notes-popup.is-shown .notes-popup-card {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.notes-popup-close {
  position: absolute;
  top: 0.75rem;
  right: 0.9rem;
  appearance: none;
  background: none;
  border: 0;
  padding: 0.25rem;
  margin: 0;
  font-size: 16px;
  line-height: 1;
  color: var(--color-mist);
  cursor: pointer;
  transition: color 0.3s;
}

@media (hover: hover) {
.notes-popup-close:hover,
.notes-popup-close:focus-visible {
  color: var(--color-ink);
}
}

.notes-popup-text {
  font-size: 0.875rem;
  line-height: 1.625;
  color: var(--color-ink);
}

/* Client, 2026-10-22: the nudge became two lines — the thought, then what it
   is. The second takes the mist the rest of the site gives a standfirst, so
   the pair reads as one statement and not two sentences of equal weight. */
.notes-popup-sub {
  margin-top: 0.35rem;
  font-size: 0.875rem;
  line-height: 1.625;
  color: var(--color-mist);
}

.notes-popup-actions {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  margin-top: 1rem;
}

.notes-popup-join,
.notes-popup-dismiss {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font-family: inherit;
  font-size: 0.75rem;
  /* no text-transform: the copy is now capitalised as written, 2026-10-22 */
  letter-spacing: 0;
  cursor: pointer;
  transition: color 0.3s;
}

.notes-popup-join {
  color: var(--color-ink);
  background-image: linear-gradient(to top, var(--color-accent), var(--color-accent));
  background-position: 0 100%;
  background-repeat: no-repeat;
  background-position: 0 calc(100% - var(--mark-lift));
  background-size: 100% var(--mark-band);
  padding-bottom: 0.15em;
}

.notes-popup-dismiss {
  color: var(--color-mist);
}

@media (hover: hover) {
.notes-popup-dismiss:hover,
.notes-popup-dismiss:focus-visible {
  color: var(--color-ink);
}
}

@media (prefers-reduced-motion: reduce) {
  .notes-popup-card {
    transition: none;
  }
}

/* ===============================================================
   People grid — an empty spacer cell after the founder's card.

   Reserves the second column of the founder's row on the two-column
   layout, so no one else's card slides up beside his; on the single
   -column mobile layout it collapses away entirely, matching how the
   real cards already stack there.
   =============================================================== */

.people-spacer {
  display: none;
}

@media (min-width: 640px) {
  .people-spacer {
    display: block;
  }
}

/* ---- Offer explorer -----------------------------------------------------
   Design review (KOMPAKTE / INTERAKTIVE DARSTELLUNG): the four additional
   areas were four long blocks stacked down the page, so you had to scroll
   past all of it to find out what was even on offer. They are now an index
   with the detail beside it — the whole list readable at a glance, every
   word of every area still there one click away.

   Progressive enhancement, deliberately: the markup is the same four
   <article>s it always was, and the index is hidden until the script marks
   the block `is-enhanced`. With JavaScript off — and for a crawler — the
   page is exactly the stacked version it used to be, with nothing hidden.

   No dividing rules between the index items, though the reference mock has
   them: the grey lines came out of this build on purpose, so the active
   item is marked with the site's own arrow and ink instead.
   ------------------------------------------------------------------------ */

.offer-index { display: none }

.offer-explorer.is-enhanced {
  display: grid;
  gap: 2.75rem;
}

.offer-explorer.is-enhanced .offer-index { display: block }

@media (min-width: 48rem) {
  .offer-explorer.is-enhanced {
    grid-template-columns: 0.8fr 1.2fr;
    gap: 4rem;
    align-items: start;
  }
  /* the index stays put while a long panel scrolls past it */
  .offer-explorer.is-enhanced .offer-index {
    position: sticky;
    top: 7rem;
  }
}

.offer-tab {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.75rem 0 0.75rem 1.6em;
  position: relative;
  font-size: var(--text-lg);
  font-weight: 400;
  /* follows h2 — it was matched to it, and 4b pulled that back */
  letter-spacing: 0.035em;
  color: var(--color-mist);
  background: none;
  cursor: pointer;
  transition: color 0.3s;
}

/* the arrow is the active marker, matching the one the CTAs now carry */
.offer-tab::before {
  content: "\2192";
  position: absolute;
  left: 0;
  opacity: 0;
  transform: translateX(-0.35em);
  transition: opacity 0.3s, transform 0.3s;
}

@media (hover: hover) {
.offer-tab:hover { color: var(--color-ink) }
}
.offer-tab[aria-selected="true"] { color: var(--color-ink) }
.offer-tab[aria-selected="true"]::before { opacity: 1; transform: none }

/* keyboard users must still be able to see where they are */
.offer-tab:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

.offer-explorer.is-enhanced .offer-panel:focus { outline: none }

.offer-explorer.is-enhanced .offer-panel {
  animation: offer-panel-in 0.45s ease both;
}

@keyframes offer-panel-in {
  from { opacity: 0; transform: translateY(10px) }
  to   { opacity: 1; transform: none }
}

@media (prefers-reduced-motion: reduce) {
  .offer-explorer.is-enhanced .offer-panel { animation: none }
  .offer-tab, .offer-tab::before { transition: none }
}

/* ---- People, single column with one swapping portrait --------------------
   Design review: the team wanted a personal layer without the page turning
   into a wall of faces. One column of names, one picture beside it, and the
   picture follows whoever you are on.

   The portrait column switches itself on. There are no photographs in the
   build yet, so the script probes for the first one and leaves the column
   off if it is not there — which means today this renders as the plain list
   the section already was, and the day the files land in
   assets/media/team/ it becomes the two-column layout with no code change.
   ------------------------------------------------------------------------ */

.people-index { display: grid }

.people-explorer.is-enhanced {
  display: grid;
  gap: 2.5rem;
  align-items: start;
}

@media (min-width: 48rem) {
  .people-explorer.is-enhanced {
    grid-template-columns: 1.35fr 0.65fr;
    gap: 4rem;
  }
  /* The picture just sits here. It was sticky, then fixed-and-parked, and
     both were rejected on the same grounds: sticky still travels a screen
     before it pins, and fixed cannot stay on screen across the section
     without hanging over the sections either side, so it had to switch on
     and off — which read as a flicker. Client's call, 2026-10-23: a plain
     picture on a page. It scrolls with everything else and is simply always
     there beside the names. */
}

.person-tab {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.9rem 0;
  background: none;
  cursor: pointer;
  font: inherit;
  transition: opacity 0.3s;
}

.person-name,
.person-role {
  display: block;
  transition: color 0.3s;
}

/* Name and role both read at body size — same tokens the body paragraphs
   use, so they track the scale and the phone step. They were 14px and 12px,
   which added two more sizes to a page that already had too many. The two
   stay apart on colour and letter-spacing instead. */
.person-name,
.person-role {
  font-size: var(--text-sm);
}

@media (min-width: 48rem) {
  .person-name,
  .person-role { font-size: var(--text-base) }
}

.person-name { font-weight: 400; letter-spacing: 0.02em }

/* 0.2em was set when this was a 12px label; at body size it adds ~3px a
   character, which pushed the three longest specialism lists onto a second
   line and made those rows taller than the rest. Pulled back so every role
   holds one line. The selector matches the shape of the label rule further up
   that would otherwise win on specificity. */
main .person-role.text-xs.tracking-\[0\.2em\] {
  letter-spacing: 0.06em;
}

/* Only meaningful once there are pictures to point at: until then every name
   reads at full strength, because dimming a list that does nothing when you
   touch it is just making it harder to read. */
.people-explorer.has-photos .person-tab[aria-pressed="false"] .person-name { color: var(--color-mist) }
@media (hover: hover) {
.people-explorer.has-photos .person-tab:hover .person-name,
.people-explorer.has-photos .person-tab[aria-pressed="true"] .person-name { color: var(--color-ink) }

.person-tab:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}
}

.people-portrait { display: none }
.people-explorer.is-enhanced .people-portrait { display: block }

.people-portrait-frame {
  aspect-ratio: 3 / 4;
  /* panel rather than panel-soft: on a #fafafa page the soft tone barely
     registers, and while this is standing in for a photograph it needs to
     read as a reserved space, the way the reference mock shows it */
  background: var(--color-panel);
  overflow: hidden;
}

.people-portrait-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.people-portrait-img.is-loaded { opacity: 1 }


/* On a phone the picture cannot sit beside the list, so it drops in under
   whoever is selected — the same idea, one person at a time. */
@media (max-width: 47.99rem) {
  /* Under the names, in the flow, scrolling with everything else. It was
     briefly sticky at the top of the section so it could be watched while
     the names went past; client, 2026-10-24: "not a floating box." So the
     grid's own single-column order does the work — list, then picture —
     and the scroll only ever changes which face is in it. */
  .people-explorer.is-enhanced .people-portrait { margin: 1.25rem 0 0.5rem }

  /* Eight names fill a phone screen on their own, so a full-size picture
     under them sat below the fold the whole time you were reading — in the
     flow and correct, but never watchable. Smaller, it shares the screen
     with the foot of the list. Driven by height with width:auto, so
     aspect-ratio holds it to 3:4. */
  .people-explorer.is-enhanced .people-portrait-frame {
    height: min(11rem, 24svh);
    width: auto;
    max-width: 15rem;
    margin-inline: auto;
  }

  /* an empty frame that jumps from name to name on a phone is just a grey
     block in the way — it only travels once it holds a face */
  .people-explorer:not(.has-photos) .people-portrait { display: none }
}

@media (prefers-reduced-motion: reduce) {
  .people-portrait-img, .person-name, .person-role, .person-tab { transition: none }
}

/* ---- The yellow marking --------------------------------------------------
   Design review (FARBAKZENTE) asked for a band that sits low and cuts through
   the lower part of the letterforms: explicitly "not a highlighter". That was
   the 0.46em band lifted 0.22em off the bottom.

   Client, 2026-10-11, having seen it in place: "get rid of all half underlines
   and make full highlights like the toolbar highlight." So the marking is now
   a highlighter after all, matched to the one the nav already uses for the
   current page — the yellow covers the word rather than striking through it.
   This overrides the designer's note; it is the client's call, made with both
   versions in front of them.

   Defined once here and used by everything yellow marks — the link and article
   hovers, the numbered labels, the notes CTA. The two values below restyle all
   of them together, which is why the half band could be retired in one edit.

   100% is the height of each mark's own padding box, so the yellow lands on
   the font's inline box exactly as the nav's field does, at whatever size the
   marked text happens to be set.
   ------------------------------------------------------------------------ */
:root {
  --mark-band: 100%;   /* full-height highlight, was a 0.46em band */
  --mark-lift: 0em;    /* nothing to lift any more: the mark fills the box */
}

/* Article titles: the compiled utility paints a flat background-colour over
   the whole word, which is the full-highlight version the review moved away
   from. Cancel it and run the same band instead, keeping the hand-drawn
   corner radius the class already carries. */
.mark {
  background-image: linear-gradient(to top, var(--color-accent), var(--color-accent));
  background-repeat: no-repeat;
  background-position: 0 calc(100% - var(--mark-lift));
  background-size: 0 var(--mark-band);
  transition: background-size 0.35s;
}

@media (hover: hover) {
.group:hover .mark,
.mark:hover {
  background-color: transparent;
  background-size: 100% var(--mark-band);
}
}

/* The 01 / 02 / 03 markers were a 2px yellow rule under the numeral — the
   exact hairline the review says disappears. Same band, same as everything
   else now. */
.border-b-2.border-accent {
  border-color: transparent;
  padding-bottom: 0;
  background-image: linear-gradient(to top, var(--color-accent), var(--color-accent));
  background-repeat: no-repeat;
  background-position: 0 calc(100% - var(--mark-lift));
  background-size: 100% var(--mark-band);
}

/* ---- Johanna only: the open entry ---------------------------------------
   Design review (EINSTIEG): keep the film, drop the step. No language gate
   and no morph — the page just scrolls — and the navigation fades in slowly
   over the footage a beat after the claim has landed, so the opening still
   reads as a room rather than as a door with a form on it.

   THIS IS THE JOHANNA / PABLA FORK. Pabla keeps the gated entry. Everything
   here hangs off `entry-open` on <body>, which only Johanna's index.html
   carries, so the two builds cannot disturb each other and the CSS stays
   mergeable.
   ------------------------------------------------------------------------ */

body.entry-open.has-splash header {
  opacity: 0;
  pointer-events: none;
  /* "langsam einblenden" — slower than any other transition in the build */
  transition: opacity 1600ms ease;
}

body.entry-open.has-splash.entry-chrome-in header {
  opacity: 1;
  pointer-events: auto;
}

/* The bar's paper backing stays tied to the scroll even though the header
   itself is now visible early. That is what lets the navigation sit directly
   on the film at the top, as drawn, and gain a background only once the film
   has moved out from under it. */
body.entry-open.has-splash header::before {
  opacity: calc(var(--splash-chrome, 0) * 0.95);
}

/* 1e: "the video then will finally disappear completely and the website will
   be all white." The shared wash stops at 0.6, which leaves the film still
   40% visible behind the page — faint, but never actually gone. Taking it
   past 1 means it reaches solid paper a little before the hero ends, so the
   last of the scroll is clean white rather than a ghost of the footage.

   Scoped to entry-open: Pabla's intro is gated, so it never scrolls and never
   washes, and its own rule clears this after the morph. */
body.entry-open.has-splash #home::after {
  opacity: calc(var(--splash-progress, 0) * 1.15);
}

/* The two slogans moved out of the film and into the page below it, so they
   are ordinary content now rather than the second half of a cross-fade. The
   base .hero-banner rule starts them at opacity 0 for the morph that this
   build no longer runs. */
body.entry-open .hero-banner {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  /* initSplash() never runs here, so --splash-chrome stays 0: the header has
     to be shown outright, and its paper backing restored, or the navigation
     would sit unreadable over the footage with no background behind it. */
  body.entry-open.has-splash header {
    opacity: 1;
    pointer-events: auto;
    transition: none;
  }
  body.entry-open.has-splash header::before {
    opacity: 0.95;
  }
}

/* ---- Johanna only: the header runs edge to edge -------------------------
   The bar carried the same 84rem cap as the page content, so on a wide screen
   the logo and the language switcher sat well inside the window with a band of
   empty space outside them. Releasing the cap lets the bar use the full width,
   keeping only the page's own gutter, so the logo sits hard left and EN | DE
   hard right.

   Only the header. The content columns below stay capped — line length is the
   reason that cap exists, and it has nothing to do with the bar.

   This file is Johanna's; Pabla keeps the centred header.
   ------------------------------------------------------------------------ */
header > .max-w-6xl {
  max-width: none;
}
/* ---- Johanna only: the scroll cue ---------------------------------------
   Correction round 5.10: the "enter" button is gone. In its place a subtle
   scroll cue, appearing at the same moment as the status bar, and from then
   on the page simply scrolls — no gate, nothing to click.

   It is a hint rather than a control: not focusable, hidden from screen
   readers, and it retires the moment you take the hint.
   ------------------------------------------------------------------------ */

.hero-scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 2.25rem;
  z-index: 3;
  /* Not white: the foot of the hero carries a 4cm gradient down to paper, so
     the cue sits on near-white and a white chevron disappears into it. Mist
     was still too light at this size — it reads as a smudge rather than an
     arrow — so it is ink held back, which keeps it quiet without losing it. */
  color: rgba(10, 10, 10, 0.6);
  pointer-events: none;
  opacity: 0;
  transform: translateX(-50%);
  transition: opacity 1200ms ease;
}

/* arrives with the bar, then breathes */
body.entry-chrome-in .hero-scroll-cue {
  opacity: 1;
  animation: hero-scroll-hint 2.6s ease-in-out 1200ms infinite;
}

/* 18x10 at a 1.2 stroke is too small to register at the foot of a full
   screen. Sized up and thickened here rather than in the markup, so the
   shape stays one line of HTML. */
.hero-scroll-cue svg {
  display: block;
  width: 26px;
  height: 15px;
  stroke-width: 1.5;
}

@keyframes hero-scroll-hint {
  0%, 100% { transform: translate(-50%, 0) }
  50%      { transform: translate(-50%, 6px) }
}

body.has-scrolled .hero-scroll-cue {
  opacity: 0;
  animation: none;
}

/* ---- 1f: coming back to the landing page within the session -------------
   The hero is NOT removed. It stays exactly where it is and renders in the
   state it ends in: all white, no film, no claim, slogans on the left — which
   is what 1f describes, and what page 4 draws with the footage already washed
   out.

   Removing it was the earlier behaviour and is wrong now: the slogans live
   inside the hero, so taking the hero away takes them with it and the landing
   page loses the very lines 1f asks for.
   ------------------------------------------------------------------------ */

/* Client, 2026-10-24: "choose a high-quality thumbnail out of the video to
   display as a still frame, one where his head is visible, and when you
   return to essential mind home that is displayed in full."

   So the returning hero keeps its full viewport and shows the frame at full
   strength — no paper over it. (The film's own poster is now
   assets/media/experts-loop-poster.jpg, the first frame of experts-loop.mp4;
   the still below is the flower, hero-still.webp.) The head sits whole
   in the upper middle; the old poster was a 17KB version of the same shot and
   far too soft to fill a screen.

   This supersedes both earlier attempts: the washed-out still of 2026-10-22
   and the blank hero it was reverted to on the 23rd. What still does not come
   back is the motion and the claim — replaying a 1.2MB file on every return
   buys nothing when the first frame is what you end up looking at. */
body.hero-sealed video.splash-media,
body.hero-sealed .splash-content {
  display: none;
}

body.hero-sealed img.splash-media {
  display: block;
  /* the push-in is driven by --splash-progress and belongs to the opening;
     a still that creeps on a page you have already seen just reads as drift */
  transform: none;
}

/* The slogans stay where the opening leaves them — lower left, over the
   frame — rather than dropping into the flow at the top of a collapsed hero. */
body.hero-sealed .hero-slogans {
  opacity: 1;
}

/* "Displayed in full": nothing over the frame at rest. It still washes out on
   scroll exactly as the opening does, so the hero hands over to white before
   the philosophy statement just as it always did. */
body.hero-sealed.has-splash #home::after,
body.entry-open.has-splash.hero-sealed #home::after {
  opacity: calc(var(--splash-progress, 0) * 1.25);
}

/* No backing on the returning hero. The bar sits straight on the still, as it
   does on the film during the opening and as the reference shows — client,
   2026-10-24: "the toolbar is still white, get rid of it when displaying the
   image." It earns its paper the same way it always has, on the scroll, once
   the picture has moved out from under it. */

/* the opening is over; the hint is not needed again */
body.hero-sealed .hero-scroll-cue {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .hero-scroll-cue { transition: none }
  body.entry-chrome-in .hero-scroll-cue { animation: none }
}

/* ---- Johanna only: the slogans over the film ---------------------------
   Correction round 5.10 (1c/1d), per Johanna page 4 "Einstieg – Alternative".

   The slogans are not a section below the film — they sit in its lower left
   corner and arrive as the footage washes out. So they are a layer of their
   own inside the hero, fading IN against --splash-progress while the claim
   above them fades OUT. The two move on the same scroll, in opposite
   directions, which is why they cannot share a container.

   The pair is not one voice: the first line carries it, the second is an
   aside underneath. Size and colour do that work, since the family has only
   one weight.
   ------------------------------------------------------------------------ */

.hero-slogans {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 3.5rem;
  z-index: 2;
  padding-inline: 1.5rem;
  pointer-events: none;
  /* In while the film washes out, and back out again before they get there:
     these are pinned to the foot of the hero, so as it scrolls up they travel
     to the top of the screen and pass under the bar — which is still
     transparent at that point, because its paper backing only arrives once the
     film is nearly gone. Without the second half of this they slide straight
     across the wordmark. Full strength around the middle of the wash, which is
     the state the reference drawing shows. */
  opacity: calc(min(
    (var(--splash-progress, 0) - 0.1) * 3,
    (0.72 - var(--splash-progress, 0)) * 9
  ));
}

@media (min-width: 48rem) {
  .hero-slogans {
    bottom: 4.5rem;
    padding-inline: 2.5rem;
  }
}

@media (min-width: 90rem) {
  .hero-slogans { padding-inline: 4rem }
}

@media (min-width: 120rem) {
  .hero-slogans { padding-inline: 6rem }
}

.hero-slogan-lead {
  max-width: 16em;
  color: var(--color-ink);
  font-size: clamp(1.25rem, 2.6vw, 2rem);
  line-height: 1.25;
  letter-spacing: 0.07em;
}

.hero-slogan-sub {
  margin-top: 0.9rem;
  color: var(--color-mist);
  /* Body size, by the same tokens the body paragraphs use rather than a
     hardcoded pixel value — so it follows the type scale if that is ever
     retuned. The clamp it replaces landed on 13px and read as a third size
     sitting between the body copy and the small labels. */
  font-size: var(--text-sm);
  line-height: 1.6;
}

@media (min-width: 48rem) {
  .hero-slogan-sub { font-size: var(--text-base) }
}

/* Reduced motion never runs the splash, so --splash-progress stays 0 and the
   calc above would hold these at zero for ever. */
@media (prefers-reduced-motion: reduce) {
  .hero-slogans { opacity: 1 }
}

/* ---- Section labels, centred and in capitals ----------------------------
   The style Johanna page 4 shows for "OUR APPROACH". Only this label uses it
   so far; the sweep across the other labels is a separate item.

   The text stays lowercase in the markup so the German dictionary — which
   keys on the exact English string — still matches it.
   ------------------------------------------------------------------------ */

.section-label {
  display: block;
  /* 4a: "align section labels to center and CAPITALIZE". The capitals come
     from CSS and the markup stays lowercase, so the German dictionary — which
     keys on the exact English string — still matches. The `lowercase` class
     was removed from these elements at the same time: in German it is
     neutralised by a rule that stops nouns being lowercased, and that rule
     would otherwise outrank this one and leave the German labels in mixed
     case while the English ones were capitals. */
  text-transform: uppercase;
  /* Centred, reversing the 2026-10-11 pass that had made left the default.
     Client, 2026-10-13: "align ALL section labels in the center, except the
     last one 'ONCE A MONTH' should stay aligned to the left." That one is
     the newsletter block's label and already has its own rule below, so the
     exception needs nothing here. */
  text-align: center;
  letter-spacing: 0.25em;
  font-size: var(--text-xs);
  color: var(--color-ink);
}

/* The newsletter band keeps its label where it is: it sits in the left cell of
   a two-column layout beside the sign-up form, not above a section, so
   centring it would park it in the middle of a column rather than the page.
   It takes the capitals and leaves the alignment. */
.section-label.text-paper\/55 {
  text-align: left;
  color: var(--color-paper);
  opacity: 0.55;
}

.vision-statement {
  margin-top: 6rem;
}

@media (min-width: 48rem) {
  .vision-statement { margin-top: 9rem }
}

/* ---- 5b: the 01 / 02 / 03 marks are drawn by the scroll -----------------
   They used to be drawn already marked, all three at once. Then they ran off
   a clock — a 700ms animation per column with a stagger, started by the
   reveal observer. Client, 2026-10-11: tie them to the scroll instead. On a
   fast scroll the timed version played after the reader had already gone
   past; on a slow one it finished before the block had settled. Either way
   the reader was watching it happen rather than causing it.

   The width now comes from `--step-fill`, which initStepMarks() writes on
   each numeral from the block's position in the viewport. No keyframes, no
   delays, no transition: a transition would lag behind the pointer and
   reintroduce exactly the decoupling this change removes. The sequencing
   lives in the JS, which hands each numeral a third of the scroll window in
   turn, and the value is latched there so scrolling back up leaves the marks
   standing.

   Scoped to `.step-marks`, which the booking columns and the practice page's
   evidence / clinical experience / your perspective list both carry — the
   practice list is a <dl>, but the JS only looks for the marker class inside
   the wrapper, so the markup shape does not matter.
   ------------------------------------------------------------------------ */

.step-marks .border-b-2.border-accent,
.step-marks .mark {
  background-size: var(--step-fill, 0%) var(--mark-band);
}

@media (prefers-reduced-motion: reduce) {
  /* initStepMarks() bails out here, so nothing would ever write --step-fill */
  .step-marks .border-b-2.border-accent {
    background-size: 100% var(--mark-band);
  }
}

/* ---- Article sources toggle ---------------------------------------------
   Client spec for On Beginning Therapy: "a discreet Sources toggle in the
   article footer, collapsed by default." Native <details>, so it works with
   no JS and the keyboard and screen-reader behaviour comes for free. Only
   the default disclosure triangle is replaced, with a +/- that matches the
   restraint of the surrounding labels.
   ------------------------------------------------------------------------ */
.article-sources > summary {
  cursor: pointer;
  list-style: none;              /* Firefox */
  transition: color 0.3s;
}

.article-sources > summary::-webkit-details-marker { display: none; }

.article-sources > summary::after {
  content: "+";
  margin-left: 0.7em;
  display: inline-block;
}

.article-sources[open] > summary::after { content: "\2013"; }

@media (hover: hover) {
  .article-sources > summary:hover { color: var(--color-ink) }
}

.article-sources ol { list-style: decimal; padding-left: 1.4em }
.article-sources li { padding-left: 0.2em }

/* Doc spec for the ADHD essay: "subdued link styling without blue text or
   persistent underlines." So no rule at rest — the link reads as body text —
   and the underline only appears under a real pointer. */
.link-subdued { color: inherit; text-decoration: none; transition: color 0.3s }

@media (hover: hover) {
  .link-subdued:hover { color: var(--color-ink); text-decoration: underline }
}

/* ---- Article photo credit ----------------------------------------------
   Client, 2026-10-19: 40% smaller than the surrounding micro-labels. Derived
   from the --text-xs token rather than hard-coded, so it keeps its ratio if
   the type scale is ever retuned.
   ------------------------------------------------------------------------ */
.article-credit { font-size: calc(var(--text-xs) * 0.6) }

/* ---- Essay title = section-heading size ---------------------------------
   Client, 2026-10-19: "make the title of the essays the same as these
   headings." Both now carry text-4xl / md:text-5xl, but page titles take a
   1pt reduction and section headings take 2pt, which left the title exactly
   1pt larger. The essay title takes the heading's reduction instead, so the
   two match to the pixel.
   ------------------------------------------------------------------------ */
main article header h1.text-4xl { font-size: calc(var(--text-4xl) - 6pt) }

@media (min-width: 48rem) {
  main article header h1.md\:text-5xl { font-size: calc(var(--text-5xl) - 10pt) }
}


/* ===============================================================
   Client review, 2026-10-22
   =============================================================== */

/* "Unify the yellow highlight style across the website. Use the same
   rectangular text highlight as in the navigation, avoiding different shapes
   and rounded corners."

   .mark carried a hand-drawn, four-corner-irregular radius; the navigation's
   active marking is a plain rectangle with a marker-pen fit. .link-mark was
   squared off in an earlier pass, so .mark is the last one out of step — it
   takes the navigation's own geometry here, not merely a squared version of
   its old one, so the two are the same highlight and not two that happen to
   both be rectangles. */
.mark {
  border-radius: 0;
  margin-inline: -0.12em;
  padding: 0 0.12em;
}

/* "Reduce the spacing between the section label (philosophy) and the text to
   create a stronger visual connection. Let the philosophy section stand more
   on its own, with generous whitespace around it. The 'core areas' heading
   should only appear when scrolling further down."

   Three things, one shape: the label and the statement close up into a single
   block, that block is centred in a section that owns a full screen, and the
   screen it owns is what keeps "core areas" out of the frame until the reader
   scrolls on. The height does the last job on its own — padding alone cannot,
   because it is the next section's label that has to be pushed out of view,
   not this section's content that has to be pushed down. */
.vision-statement {
  margin-top: 2rem;
}

@media (min-width: 48rem) {
  .vision-statement { margin-top: 2.5rem }
}

#vision > div {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* The body size and leading went up on 2026-10-22 and came straight back down
   on 2026-10-23: "revert these changes, go back to smaller font and a bit of
   spacing." --type-body is back at its old value above, and the leading
   override that went with it is gone, so body copy is once more Tailwind's
   own leading-relaxed. */


/* Client, 2026-10-24: "increase a bit more contrast between the grey text and
   the grey background." --color-mist went from #8a8a8a to #6e6e6e just above,
   which takes body-grey on the #f1f1f1 form panel from 3.05:1 to 4.5:1 and on
   the #fafafa page from 3.31:1 to 4.87:1 — the readable threshold on both.

   The field placeholders were the faintest thing on that panel by some way:
   mist at 60% landed near 1.9:1, lighter than the label sitting above the
   field. At 80% they are still plainly secondary to a typed value without
   disappearing into the panel. */
.placeholder\:text-mist\/60::placeholder {
  color: color-mix(in oklab, var(--color-mist) 80%, transparent);
}


/* Client, 2026-10-24: "make sure the notes highlighting on the essay titles
   scroll highlight is working (on the mobile version)."

   The hover rule that draws this band lives in @media (hover: hover), so on a
   phone the article titles never carried it. initScrollMarks() hands the class
   to whichever card is being read; the band, the wipe and the timing are the
   hover ones, unchanged. */
@media (max-width: 47.99rem) {
  .mark.is-marked {
    background-size: 100% var(--mark-band);
  }
}


/* Client, 2026-10-24: "on the mobile this sits a bit low on the screen, make
   it up the top — and only see that, then scroll down to philosophy."

   The two lines are pinned to the foot of the hero, which is right on a wide
   screen: the film has room above them and they sit in its lower left corner
   as drawn. On a phone the hero is one tall column, so the foot is simply the
   bottom edge of the screen — they came out at 669px of an 812px viewport,
   with nothing under them. Here they go to the top instead, just clear of the
   bar, and the rest of the hero stays empty until the scroll reaches the
   philosophy statement.

   Scoped away from .hero-sealed: on a return the pair is already in normal
   flow at the top of a collapsed hero, and top/bottom mean nothing there. */
@media (max-width: 47.99rem) {
  body:not(.hero-sealed) .hero-slogans {
    top: calc(var(--header-h, 96px) + 1.5rem);
    bottom: auto;
  }
}


/* Client, 2026-10-24: "the philosophy paragraph looks funny because of the
   lines it takes up — make it go across 3 instead of 4 (on mobile)."

   The <br> between the two sentences is right on a wide screen: one sentence
   per line, two lines, as drawn. At phone width the first sentence no longer
   fits on one line, so the break left "lives." stranded on a line of its own
   32px wide, and the paragraph ran to four. Letting the sentences flow into
   each other gives three full lines and no orphan.

   The space this leans on is in the markup, immediately before the <br>, so
   that with the break gone the two sentences do not run together. */
@media (max-width: 47.99rem) {
  .vision-statement br {
    display: none;
  }
}


/* Client, 2026-10-24: "bring core areas a bit closer to the content, maybe a
   line or two."

   The label sits in its own .reveal wrapper as a flex item, so what separates
   it from the block beneath is the column's gap — 96px on desktop, 64px on a
   phone, the same gap that spaces the service blocks from each other. Pulling
   the gap itself in would close those up too, so the label's own wrapper
   gives back a couple of lines instead and nothing else moves.

   :has() rather than a class, so it applies wherever the pattern appears —
   core areas and additional areas, landing page and practice page — and
   cannot drift apart between them. */
main .flex.flex-col > .reveal:has(> .section-label) {
  /* Down one line, client 2026-10-24 — the label was sitting high in its own
     section with the content a long way under it. The margin below still
     pulls it towards that content; this just drops the pair as a whole.
     Down two lines further, client 2026-10-25: "bring this header down two
     lines to match the other headings spacing." Same step as before, three
     times over; the negative margin below is untouched, so the label keeps
     the distance to its content and the pair simply sits lower. */
  margin-top: 4.5rem;
  margin-bottom: -1.25rem;
}

@media (min-width: 48rem) {
  main .flex.flex-col > .reveal:has(> .section-label) {
    margin-top: 5.25rem;
    margin-bottom: -2.5rem;
  }
}


/* Client, 2026-10-24, four notes on the landing page.

   1. "Are the headers (Psychiatry, Psychotherapy, People, Library) all the
      same size?" They were not: the first two sat on text-4xl/md:text-5xl at
      24.1px, People and Library a step below at 20.1px. The two markup
      classes are changed to match rather than adding an override, so the
      heading step stays the single place these sizes come from. */

/* 2. "Is PHILOSOPHY the same spacing [as core areas]? Make it the same."
      It was not: 40px against the 56px under core areas. Matched to it at
      both widths. This loosens the gap that was tightened on 2026-10-22 —
      deliberately, because consistency with the other labels now wins. */
.vision-statement {
  margin-top: 2.75rem;
}

@media (min-width: 48rem) {
  .vision-statement { margin-top: 3.5rem }
}

/* 3. "This heading is a bit far from the text" — People to its list. The
      explorer carries mt-16, which left 50px of clear air under the
      heading. */
#people .people-explorer {
  margin-top: 2rem;
}

@media (min-width: 48rem) {
  #people .people-explorer { margin-top: 3rem }
}

/* 4. "The scroll-over effect is too wide — only change the picture if you
      scroll over the names." The row is a full-width block button, so the
      whole column width was a hover target, including the empty space out to
      the right. The name now shrinks to its own text and takes the hover
      (see initPeopleExplorer); the button keeps its full width so the tap
      target on a phone is unchanged. */
.person-name {
  width: fit-content;
}


/* Client, 2026-10-24: "maybe [the notification] window a bit bigger and/or
   the font a bit smaller, so the text has a bit more air to breathe."

   Wider rather than smaller: the copy in it is already the smallest reading
   size on the site, and shrinking it further would work against the contrast
   pass from earlier today. The card gains 4rem of width and a little more
   padding on every side, so the two lines have room without the type moving. */
.notes-popup-card {
  max-width: 26rem;
  /* Client, 2026-10-24: "make this touch the edges more." The card got wider
     a moment ago and the padding went up with it, which on the new width read
     as too much air around a short message. The box keeps its size; the
     content moves out towards the edges. The right side keeps more than the
     others because the close button sits in it. */
  padding: 1.1rem 2.25rem 1.1rem 1.25rem;
}

/* max-width alone did nothing here. Above 640px the wrapper is anchored to
   the right with `left: auto`, so it shrink-wraps to its content — which
   makes the card's `width: 100%` resolve against its own content width and
   the cap never bind. A real width is what widens it; the wrapper still
   hugs it on the right. Below 640px the wrapper spans the screen and
   `width: 100%` already does the job, so this stays on desktop. */
@media (min-width: 640px) {
  .notes-popup-card { width: 26rem }
}


/* Client, 2026-10-24: "'Begin with what matters' at the end — make it a bit
   smaller, more subtle, less advertising."

   It sat on md:text-6xl at 41.5px, the loudest thing on the page by a long
   way. The next step down the shared scale is 24.1px, which is the size of
   the section headings and too quiet for a closing line, so this one takes a
   size of its own between them. Scoped to #booking so the heading steps the
   rest of the page shares are untouched, and to md and up because the mobile
   size (20.1px) was never the problem. */
@media (min-width: 48rem) {
  #booking h2 {
    font-size: calc(var(--text-5xl) - 4pt);
  }
}


/* The timed draw was removed on 2026-10-25 — the marks follow the scroll
   only — and its slower transition went with it. */


/* Client, 2026-10-24.

   1. "The markers don't reach the end of the arrow." The arrow is a ::after
      that slides 0.2em to the right on hover — 3.01px on these — but the
      element's box, and so the yellow painted across it, stayed where it
      was, leaving the arrowhead hanging outside the marking. The box now
      carries that much padding on the right, so the travel happens inside
      it. Nothing moves at rest, because the marking is only drawn on hover.
      One rule covers every one of them: the arrow comes from a single
      ::after on .link-mark. */
.link-mark {
  padding-right: 0.2em;
}

/* 2 and 3. "The overline looks better, but a tiny bit less spaced and a tiny
   bit smaller — and match it with the bottom of the website."

   The footer links already carried tracking-[0.25em] in the markup and were
   rendering at letter-spacing: normal, because this build's compiled Tailwind
   flattens every arbitrary tracking to 0 and the rule that puts it back was
   scoped to `main`. The footer sits outside main, so it never got it. That is
   the whole reason the two did not match. Both are now set here, together, at
   the slightly smaller and slightly tighter values. */
main .text-xs.tracking-\[0\.25em\]:not(.link-mark),
footer .text-xs.tracking-\[0\.25em\] {
  font-size: 0.6875rem;
  letter-spacing: 0.2em;
}

/* Footer nav sits centred on the page width, not wherever justify-between
   leaves it between the brand lockup and the copyright line, which are
   different widths. The two outer blocks take equal flex, so the nav lands
   on the true centre. Only the site footer (bg-paper); the essay footers
   are a different element. */
@media (min-width: 48rem) {
  footer.bg-paper > div > p {
    flex: 1 1 0;
    min-width: 0;
  }
  footer.bg-paper > div > p:first-child {
    text-align: left;
  }
  footer.bg-paper > div > p:last-child {
    text-align: right;
  }
  footer.bg-paper > div > nav {
    flex: 0 0 auto;
    justify-content: center;
  }
}

/* Mobile menu: the closed panel must be out of the tab order and out of the
   accessibility tree, not merely transparent. `inert` does that in current
   browsers; visibility:hidden covers the rest, and is held back until the
   fade-out has finished so the panel still animates on the way out. */
.site-mobile-nav {
  visibility: hidden;
  transition: opacity 0.5s, visibility 0s linear 0.5s;
}
.site-mobile-nav.is-open {
  visibility: visible;
  transition: opacity 0.5s, visibility 0s;
}
/* The panel's links carry `transition-all`, so the visibility they inherit
   from the panel is itself transitioned and — being a discrete property —
   only flips at the halfway point of the 500ms fade. That left them
   unfocusable for the first 250ms, which is exactly when the menu moves
   focus onto the first one. Transition what actually animates. */
.site-mobile-nav nav > a {
  transition-property: opacity, transform, translate;
}

/* Highlight yellow, 2026-10-25: RAL 1026 (luminous yellow, #ffff00) in place
   of the old #fff500, carried at 70% so the marks sit a shade lighter over
   the paper. Everything yellow reads off --color-accent, so the token itself
   changes; the focus rings keep the solid colour, because a keyboard ring
   that fades is a step backwards. */
:root {
  --color-accent: rgba(255, 255, 0, 0.7);
  --color-accent-solid: #ffff00;
}
.offer-tab:focus-visible,
.person-tab:focus-visible {
  outline-color: var(--color-accent-solid);
}

/* Client, 2026-10-25: "delayed notification needs to be 10 percent bigger on
   the box and the text needs to reach the edge of the box."

   The card was a fixed 26rem while the copy ran to about 215px, so two short
   lines sat in the left 40% of it. It now hugs its own content, and the 10%
   comes from scaling what is inside: type and padding both go up a tenth, so
   the box grows with the text instead of around it, and the lines end at the
   padding in every language — German runs longer than English and the card
   simply follows. */
.notes-popup-card {
  width: fit-content;
  max-width: 100%;
  padding: 1.21rem 2.475rem 1.21rem 1.375rem;
}
@media (min-width: 640px) {
  .notes-popup-card {
    width: fit-content;
  }
}
.notes-popup-text,
.notes-popup-sub {
  font-size: 0.9625rem;
}
.notes-popup-join,
.notes-popup-dismiss {
  font-size: 0.825rem;
}

/* Client, 2026-10-25: the brand lockup in the footer went left-aligned when
   the nav was centred — giving the two outer blocks equal flex made the
   lockup's own `text-align: center` (what stacks "mind" under "essential")
   read as centring inside half the row, so it had to be overridden. Centre
   the nav on the container instead: the brand and the copyright go back to
   hugging their content at either end, and the lockup keeps its own centre. */
@media (min-width: 48rem) {
  footer.bg-paper > div {
    position: relative;
  }
  footer.bg-paper > div > p {
    flex: 0 1 auto;
  }
  footer.bg-paper > div > p:first-child {
    text-align: center;
  }
  footer.bg-paper > div > nav {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
  }
}

/* Client, 2026-10-27: "make all of these titles smaller by 15 percent" —
   desktop only, the overlines above each section (CORE AREAS, ADDITIONAL
   AREAS, PHILOSOPHY, THE SPACE, ONCE A MONTH), landing page and practice
   page alike. 0.75rem → 0.6375rem. The phone keeps the size it has, where
   the label is already small against the width of the screen. */
@media (min-width: 48rem) {
  .section-label {
    font-size: calc(var(--text-xs) * 0.85);
  }
}

/* And "bring the core areas on the subsite down one line" — the practice
   page only, so it is a class on that one wrapper rather than another
   :has() rule that would move the landing page with it. One line is the
   same step the earlier moves used: 1.75rem on desktop.

   Client, 2026-10-29: "core areas and additional areas should have approx
   the same distance from the text — still quite a difference." Measured on
   the practice page, the gap above the label was 192px for CORE AREAS and
   194px for ADDITIONAL AREAS on desktop, but 176px against 151px on a
   phone: what sits above each label contributes about 26px more to ADDITIONAL
   on desktop and nothing on mobile, so the step that balances the one
   unbalances the other. It is therefore desktop-only now, and the phone
   falls back to the shared 4.5rem — 152px against 151px. */
@media (min-width: 48rem) {
  main .flex.flex-col > .reveal.label-step-down {
    margin-top: 7rem;
  }
}

/* Client, 2026-10-27: "love the lemon colour now, but can we make them a bit
   more transparent, aquarell / watercolour like?"

   A highlighter pen does not lay down one flat tone: the ink pools where the
   nib overlaps, thins where it lifts, and the stroke has soft ends. So the
   flat fill becomes two stacked washes — one running along the stroke, which
   gives the uneven density and the fade at either end, and one across it,
   which makes the ink settle towards the baseline. Peak opacity lands near
   0.5 against the 0.7 it was, so the paper reads through it.

   Client, 2026-10-29: "the new transparent marking is great, but very pale
   now. should be a tiny bit stronger again, still transparent." Every alpha
   in the stack below is the 2026-10-27 value times 1.3, and --accent-fill
   with it, so the mottling, the soft ends and the baseline settle are
   unchanged in shape — only the ink is heavier. Composite peak sits near
   0.55, still well under the flat 0.7 it started at. 1.2 was tried first
   and read as no change at all next to the old one; 1.45 started to look
   like the flat fill again.

   Both layers live in one token, and a single `background-size` applies to
   every layer of a background, so the fill animations that size these marks
   — the scroll-driven numerals, the nav mark, the hover reveal — keep
   working untouched. */
:root {
  --mark-wash:
    /* pigment pooling where the nib lingered */
    radial-gradient(58% 120% at 21% 88%,
      rgba(255, 255, 0, 0.13) 0%,
      rgba(255, 255, 0, 0.052) 46%,
      rgba(255, 255, 0, 0) 72%),
    radial-gradient(42% 105% at 74% 18%,
      rgba(255, 255, 0, 0.117) 0%,
      rgba(255, 255, 0, 0.039) 50%,
      rgba(255, 255, 0, 0) 70%),
    /* two passes of the pen, slightly off each other, so the overlaps
       mottle instead of reading as one even tone */
    linear-gradient(94deg,
      rgba(255, 255, 0, 0) 0%,
      rgba(255, 255, 0, 0.13) 4%,
      rgba(255, 255, 0, 0.039) 23%,
      rgba(255, 255, 0, 0.156) 45%,
      rgba(255, 255, 0, 0.026) 64%,
      rgba(255, 255, 0, 0.143) 87%,
      rgba(255, 255, 0, 0.065) 96%,
      rgba(255, 255, 0, 0) 100%),
    linear-gradient(86deg,
      rgba(255, 255, 0, 0) 0%,
      rgba(255, 255, 0, 0.078) 11%,
      rgba(255, 255, 0, 0.13) 32%,
      rgba(255, 255, 0, 0.026) 55%,
      rgba(255, 255, 0, 0.117) 76%,
      rgba(255, 255, 0, 0.039) 93%,
      rgba(255, 255, 0, 0) 100%),
    /* the ink settling towards the baseline, feathered top and bottom so
       the band has no ruled edge */
    linear-gradient(to top,
      rgba(255, 255, 0, 0) 0%,
      rgba(255, 255, 0, 0.195) 7%,
      rgba(255, 255, 0, 0.143) 40%,
      rgba(255, 255, 0, 0.208) 74%,
      rgba(255, 255, 0, 0.091) 93%,
      rgba(255, 255, 0, 0) 100%);
}

.link-mark,
.nav-mark,
.mark,
.border-b-2.border-accent,
.notes-popup-join {
  background-image: var(--mark-wash);
}

/* The essay-card titles paint on hover with a flat background-colour rather
   than the band, so they need the wash handing to them the same way. */
.mark.group-hover\:bg-accent:is(:where(.group):hover *) {
  background-color: transparent;
  background-size: 100% var(--mark-band);
}

/* Client, 2026-10-27: "10 percent fainter, and apply to all highlights site
   wide." The wash above lost a tenth of its opacity; this is the second half
   — the yellow fields that were still painted flat, so nothing on the site
   reads as a solid block of lemon next to a washed one.

   The current-page nav item turned the gradient off on purpose when it was a
   solid field; it takes the wash instead. Same for the small arrow squares
   and the accent rule.

   The hover fills are the exception, and deliberately: their colour drains
   back over 1200ms, a transition that only works on background-color, and a
   gradient cannot carry it. They keep the colour and take the wash's weight
   (0.42, raised with it on 2026-10-29) instead of the 0.7 they had, so they sit at the same strength as
   everything else without losing the motion. */
:root {
  --accent-fill: rgba(255, 255, 0, 0.42);
}

.nav-mark-active,
.accent-rule,
.bg-accent {
  background-color: transparent;
  background-image: var(--mark-wash);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: 0 0;
}

@media (hover: hover) {
  .hover\:bg-accent:hover,
  header nav a.border-ink.nav-cta-active:hover {
    background-color: var(--accent-fill);
  }
}
header nav a.border-ink:active {
  background-color: var(--accent-fill);
}

/* Client, 2026-10-27: "double the size of the rectangle and make it more
   opaque." 235 x 134 becomes 470 x 268 — the panel no longer sizes itself
   to the copy, so German and English share one rectangle — and the paper
   behind it goes from 85% to 97%, which is near solid over the article
   while the blur still softens what shows through at the edges. The copy
   keeps its size and centres in the taller box. */
.notes-popup-card {
  width: 470px;
  max-width: 100%;
  /* Client, 2026-10-27: cropped 20% vertically, 268px -> 214px. */
  min-height: 214px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 1.75rem 2.5rem 1.75rem 2rem;
  background: #fafafaf7;
  background: color-mix(in oklab, var(--color-paper) 97%, transparent);
}

/* Client, 2026-10-27: "don't change the font size, just make the text reach
   the borders." So the type goes back to what it was and the layout does the
   work instead: the copy sits against the top of the rectangle, the two
   actions against the bottom and spread to either side, and the padding
   comes in to a thin margin. The content spans the doubled box rather than
   clustering in the middle of it. */
.notes-popup-card {
  /* flex-start, not space-between: with three children the even
     distribution floated the standfirst in the middle of the box, away
     from the line it belongs to. The pair stays at the top and the
     actions are pushed to the bottom with an auto margin instead. */
  justify-content: flex-start;
  padding: 1.25rem 1.5rem 1.25rem 1.5rem;
}
.notes-popup-text,
.notes-popup-sub {
  font-size: 0.9625rem;
  line-height: 1.625;
}
.notes-popup-sub {
  margin-top: 0.35rem;
}
.notes-popup-join,
.notes-popup-dismiss {
  font-size: 0.825rem;
  white-space: nowrap;
}
.notes-popup-actions {
  justify-content: space-between;
  gap: 1.5rem;
  margin-top: auto;
}
.notes-popup-close {
  top: 0.75rem;
  right: 0.9rem;
  font-size: 16px;
}

/* Client, 2026-10-29: "with the space to breathe for the notification I
   meant more on the outside, not in the middle — move the text more to the
   middle." The pass above had pinned the copy to the top of the rectangle
   and the actions to the bottom, which opened a hole between the standfirst
   and the two buttons instead of giving the panel a margin. So the three
   lines group and centre, the actions sit a fixed step under the copy, and
   the height that is left over falls where it was wanted: around the
   outside. One rule, so English and German and both widths move together. */
.notes-popup-card {
  justify-content: center;
  padding: 1.75rem 2rem;
}
.notes-popup-actions {
  margin-top: 1.75rem;
}

/* Client, 2026-10-28, the mobile menu: "make font small, and the yellow
   button make rectangle" — 30px links come down to 24px. Phone only; the
   panel never shows above 640px. */
.site-mobile-nav nav > a {
  font-size: 1.5rem;
}

/* Client, 2026-10-29, with a sketch of the word boxed in: "the booking
   button, make it rectangular similar to the website". The yellow square
   holding the arrow is gone from the markup; the link itself now carries
   the box, which is the shape the header's own booking control has. The
   panel's nav is a flex column set to align-items: flex-start, so the box
   hugs the word on its own and needs no width.

   Then, same day: "make it black, and when you click it turns yellow." So
   the box is filled ink with paper type, and pressed, the fill drops away
   and the wash comes through — the same yellow every other mark on the
   site is painted with.

   And last: "a tiny bit smaller, and centre it — just the booking, leave
   everything else the same." The earlier left-alignment of the word is off
   again, because centring the box is what the client now wants; align-self
   does it on this one item, so the four links above stay where they are.
   The padding is in em, so a single font-size step takes the whole box down
   with it. 24px -> 21.6px took 142 x 53 to 128 x 48; "still too big, make
   it 10% smaller" took 21.6px -> 19.44px and the box to 116 x 43; and
   "maybe 5% smaller again" lands on 18.47px and 110 x 41. */
.site-mobile-nav nav > a.mobile-nav-cta {
  align-self: center;
  border: 1px solid var(--color-ink);
  background-color: var(--color-ink);
  color: var(--color-paper);
  font-size: 1.154rem;
  padding: 0.4667em 1.0667em;
  margin-top: 1.25rem;
  /* No transition: a 200ms crossfade meant the wash sat over a fading black
     for a moment, and a tap is often over before the yellow had arrived. */
  -webkit-tap-highlight-color: transparent;
}
.site-mobile-nav nav > a.mobile-nav-cta:active,
.site-mobile-nav nav > a.mobile-nav-cta.is-pressed {
  background-color: transparent;
  background-image: var(--mark-wash);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: 0 0;
  color: var(--color-ink);
}

/* Client, 2026-10-28: "in the mobile version make the image at the top of
   the names so you can see it flick through when you scroll." It was under
   the list, which meant that while you were reading the names the picture
   was below the fold and the flicking happened out of sight.

   So it moves above them — and it has to hold there, or it would scroll
   away after the first two names and be just as invisible. The explorer
   becomes a flex column on the phone, which gives the portrait the whole
   block to travel in (as a grid item its cell was only as tall as itself,
   which is why the earlier attempt at this never moved), and it sticks
   just under the header while the list goes past beneath it.

   This is the pinning the 2026-10-24 note rejected as "a floating box" —
   the difference is that it is now at the top of the list rather than
   parked over the middle of it, and it scrolls in and out with the section
   like anything else. */
@media (max-width: 47.99rem) {
  .people-explorer.is-enhanced {
    display: flex;
    flex-direction: column;
  }

  /* Fixed, not sticky, while the names pass — see initPeoplePin(). The
     sticky rule below stays as the fallback for a browser that runs the
     CSS but not the script. */
  .people-explorer.is-portrait-pinned .people-portrait {
    position: fixed;
    z-index: 30;
  }

  .people-explorer.is-enhanced .people-portrait {
    order: -1;
    position: sticky;
    /* Flush under the sticky header (82px) once it pins. The extra 3.5rem
       is the lift given to the frame below: client, 2026-10-28, "it could
       appear a bit earlier already and start moving down together with the
       scrolling", so the picture starts up beside the People heading and
       travels with the page until it reaches the header. */
    /* 1.5rem of air between the header and the picture — client,
       2026-10-28: "so that the pic is rather floating in the air through
       the site than dangling down the header section." */
    top: calc(5.125rem + 1.5rem + 8.25rem);
    z-index: 2;
    /* Client, 2026-10-28: "get rid of the white sides — just have the
       profile picture hover over the names, not a rectangle." So the band
       is gone: the element is only as wide as the picture, centred, with
       nothing behind it. The picture itself is opaque, so the names it
       covers are hidden and the rest of each line stays visible beside
       it. */
    /* Client, 2026-10-28: "move it a bit to the right so that the title
       'People' can be moved closer to the text again." The picture takes
       no height in the column any more — the list starts straight under
       the heading — and the frame hangs off the right-hand side, over the
       names rather than above them. */
    align-self: stretch;
    background: none;
    padding: 0;
    margin: 0;
    height: 0;
  }

  .people-explorer.is-enhanced .people-portrait-frame {
    position: absolute;
    /* Client, 2026-10-28: "start the image slightly above Sven Briken's
       name so it doesn't cover his name." Lifted 132px — the frame's
       bottom now sits about 10px clear of the first name, and the pin
       offset above carries the same figure so it still lands flush under
       the header once it catches. */
    top: -8.25rem;
    right: 0;
  }
}

/* Client, 2026-10-28, the footer on a phone: "maybe the (c) 2026 essential
   mind on the bottom right and smaller font." Three left-aligned blocks of
   near-equal weight stacked at even spacing is what read as messy; the
   copyright now sits to the right, a size below the links, so it closes the
   column rather than repeating it. The stack is a little tighter with it. */
@media (max-width: 47.99rem) {
  footer.bg-paper > div {
    gap: 1.75rem;
  }
  /* the four links were breaking after "experiences" and dropping imprint
     onto a line of its own, which is half of what looked untidy — a
     smaller gap keeps the row intact at 375px */
  footer.bg-paper > div > nav {
    gap: 1.1rem;
    justify-content: center;
  }
  footer.bg-paper > div > p:last-child {
    text-align: right;
    font-size: 0.625rem;
  }
}

/* Client, 2026-10-28: "once a month and the curated body text should be
   smaller, but still similar sizes to other fonts on the website."

   The standfirst in the newsletter band was the outlier — 18.7px against
   the 15px the vision statement and the section copy run at, which is why
   it crowded "The Essential Notes" above it. It now takes the body scale:
   16.9px on desktop, 15px on a phone, the same value as the vision
   statement, so it reads as the site's standfirst rather than a second
   heading.

   The overline was already at the site's label size, but only desktop got
   the 15% reduction earlier today — the phone was still at 12px while the
   heading beside it stayed large. The reduction now applies at every
   width, so every overline on the site matches. */
#notes p.font-serif {
  font-size: calc(var(--text-base) * var(--type-body));
}
.section-label {
  font-size: calc(var(--text-xs) * 0.85);
}
@media (min-width: 48rem) {
  #notes p.font-serif {
    font-size: calc(var(--text-lg) * var(--type-body));
  }
}

/* Client, 2026-10-29, circling ONCE A MONTH and CORE AREAS on a phone:
   "the overliners still a tiny bit smaller — mobile version site wide,
   down by 10%." Desktop keeps 0.85 of the label size; the phone goes to
   0.765 of it, so 9.18px against the 10.2px above 768px. Every overline
   reads off the one class, so this is the whole site at once. */
@media (max-width: 47.99rem) {
  .section-label {
    font-size: calc(var(--text-xs) * 0.765);
  }
}

/* Client, 2026-10-28: "The Essential Notes — difficult to have it in 1
   line? Maybe alternative in 3 lines then?" One line is possible: at 375px
   the title needs 355px against the 327px it has, so it only has to come
   down about a tenth. The size is tied to the viewport so it holds on a
   narrower phone too, and it is capped at the size the heading already has
   — on a wide phone nothing changes at all.

   The Library title came next and is the longer of the two, so the ratio
   is set by that one and both pages share it: the two titles then match
   each other across the site instead of being sized one by one. The other
   page titles are short enough to need nothing. */
@media (max-width: 47.99rem) {
  /* `main h1.text-5xl` sets the page-title size, so this has to outrank it */
  main h1.h1-fit.text-5xl {
    font-size: min(calc(var(--text-5xl) - 1pt), calc(9.5vw - 5px));
  }
}

/* Client, 2026-10-28: "a little bit more space to breathe between these two
   sections." The studio block runs straight into People on a phone, and the
   portrait now floats up into that gap, so the People section takes another
   48px above it: 112 -> 160. Phone only. */
@media (max-width: 47.99rem) {
  #people {
    /* 112 -> 160 -> 192px, client asking twice for more air here */
    padding-top: 12rem;
  }
}

/* Client, 2026-10-28: "move the People down one line", then another, and
   again on 2026-10-30 — three lines in all, at the phone's 1.5rem step.
   The heading only; the list and the portrait follow it in flow, so the
   24px it now sits above the first name is unchanged. Phone only, which
   is where all three requests were made. */
@media (max-width: 47.99rem) {
  #people > .reveal:first-child {
    margin-top: 4.5rem;
  }
}

/* Client, 2026-10-29: "the gap is still too large between the title and
   Psychiatry."

   105px of it on desktop, 92px on a phone, against 42px and 30px under
   ADDITIONAL AREAS — and almost half of it was invisible. Each core-area
   card carries `border-t border-line pt-12`: a rule with 48px of air under
   it. But `.border-line` was neutralised site-wide back when the hairlines
   came out, so that border has been transparent for weeks and the padding
   has been holding space for a line nobody can see.

   Between two cards the padding still does its job, so only the first card
   in the list loses it — the one whose rule the section label has already
   replaced. Desktop goes to 57px and the phone to 45px, both now within
   15px of what sits under ADDITIONAL AREAS. */
main .flex.flex-col > .reveal:has(> .section-label) + div > article:first-child {
  padding-top: 0;
}

/* Client, 2026-10-29: "make the box 10 percent smaller, keep everything
   else the same — both mobile and desktop."

   The rectangle and its padding scale; the type does not, so the copy is
   untouched and only the frame around it closes in. 470 x 214 becomes
   423 x 193, and on a phone the card was never 470 wide in the first place
   — it filled the container — so there the 10% has to come off the cap
   instead: max-width 90% takes 327px to 294px.

   That cap has to stay on the phone. Above 640px the wrapper shrink-wraps
   to the card (see the note on `width: 26rem` further up), so a percentage
   there resolves against the card's own width and quietly takes a second
   10% off: 423 came out as 381. */
.notes-popup-card {
  width: 423px;
  max-width: 100%;
  min-height: 193px;
  padding: 1.575rem 1.8rem;
}
@media (max-width: 47.99rem) {
  .notes-popup-card {
    max-width: 90%;
  }
}

/* The other half of the same report. Every form control on the site is
   `text-sm` — 14px — and iOS Safari zooms the whole page in whenever a
   field it focuses is under 16px, which on its own reads as the page
   jumping away. 16px on a phone is the only fix that leaves pinch-zoom
   working; capping maximum-scale in the viewport meta would stop the zoom
   by taking zooming away from everyone. Phones only: the desktop fields
   keep 14px. */
@media (max-width: 47.99rem) {
  input,
  textarea,
  select {
    font-size: 16px;
  }
}

/* Client, 2026-10-30: "when I am on the practice subsite it has a weird
   square box."

   The box is the arrow. It is drawn as `content: "\2192"` on .link-mark
   and inherits the body face — and reading the font binary
   (ABCP3rman3nt_Book, the `permanent` face), U+2192 is not in its cmap at
   all: it maps to glyph 0, .notdef. Desktop browsers quietly substitute
   the character from the next family in the stack, which is why it has
   always looked right here; iOS Safari draws the .notdef box instead.

   So the arrow is handed to a face that actually has the glyph rather
   than left to per-glyph fallback. It was being drawn by one of these
   anyway on every browser that got it right, so nothing changes visually
   where it already worked. Every .link-mark arrow on the site is this one
   pseudo-element, so the menu, the CTAs and the card links are all
   covered. */
.link-mark:not([href^="mailto:"]):not([href^="tel:"])::after {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

/* Client, 2026-10-30: "People is quite far from the text, but Library is
   very close — make the People title match the Library spacing."

   Measured on the landing page, heading to the first line under it:
   Library 24px at both widths, People 34px on desktop and 58px on a phone.
   Two separate causes. The explorer's own top margin is the desktop half.
   The phone adds the rest: the explorer becomes a flex column there, and
   its 40px row gap falls between the list and the sticky portrait — which
   is a zero-height anchor, so that gap is pure dead space sitting directly
   under the heading. */
#people .people-explorer {
  /* Corrected 2026-10-30. The first pass set 2.375rem by measuring against
     Library — but measured it while the heading was still in its reveal,
     translated 14px down. Library's standfirst sits inside the same reveal
     wrapper as its heading, so the two move together and its gap reads 24px
     in any state; People's list is a sibling outside the wrapper, so the
     heading rises 14px away from it when the reveal lands and the gap the
     reader actually sees was 38px, not 24px. 1.5rem is the settled 24. */
  margin-top: 1.5rem;
}
@media (max-width: 47.99rem) {
  #people .people-explorer.is-enhanced {
    row-gap: 0;
  }
}

/* Client, 2026-10-30: "love the transparent lemon marking (could be even
   more neon-lemony), but it's a bit too pale now — sometimes hard to see,
   especially the short numbers 01 02 03. Stronger again, or better: a fade,
   strong where the marker first touches the page and fading towards the
   end. For that it should probably be a tiny bit longer than the text."

   So the wash stops being an even field and becomes a stroke with a
   direction. Every layer now ramps left to right: the pigment pools where
   the nib lands, the two pen passes start at full pressure and lift, and
   only the baseline settle stays even, because that is the ink sinking
   rather than the hand moving. Composite peak is about 0.75 at the entry
   against the 0.55 flat it replaces — brighter and more neon at the start
   than anything here has been since the flat fill — tapering to about 0.23
   at the tail, so the paper comes back through as the stroke leaves.

   The ramp is gentle through the first half on purpose. 01, 02 and 03 are
   two characters wide, and a fade that fell away early would leave half of
   a short mark paler than it is today rather than stronger.

   One token, no media queries, so the phone and the desktop move together.
   Percentages throughout, so the scroll-driven fills and the hover reveals
   that animate background-size keep working untouched. */
:root {
  --mark-wash:
    /* the nib lands: the heaviest pigment, near the start of the stroke */
    radial-gradient(40% 130% at 8% 60%,
      rgba(255, 255, 0, 0.42) 0%,
      rgba(255, 255, 0, 0.16) 55%,
      rgba(255, 255, 0, 0) 80%),
    /* a second, lighter pool a third in, so the start is not one blob */
    radial-gradient(45% 115% at 34% 30%,
      rgba(255, 255, 0, 0.22) 0%,
      rgba(255, 255, 0, 0.07) 55%,
      rgba(255, 255, 0, 0) 78%),
    /* the stroke itself, full pressure at the left, lifting towards the
       right; slightly off-horizontal so it never reads as a printed bar */
    linear-gradient(93deg,
      rgba(255, 255, 0, 0.34) 0%,
      rgba(255, 255, 0, 0.3) 18%,
      rgba(255, 255, 0, 0.22) 42%,
      rgba(255, 255, 0, 0.14) 66%,
      rgba(255, 255, 0, 0.07) 86%,
      rgba(255, 255, 0, 0.02) 96%,
      rgba(255, 255, 0, 0) 100%),
    /* the return pass, off the other way, mottling where the two overlap */
    linear-gradient(87deg,
      rgba(255, 255, 0, 0.2) 0%,
      rgba(255, 255, 0, 0.1) 22%,
      rgba(255, 255, 0, 0.17) 45%,
      rgba(255, 255, 0, 0.06) 70%,
      rgba(255, 255, 0, 0.03) 88%,
      rgba(255, 255, 0, 0) 100%),
    /* the ink settling to the baseline, feathered top and bottom so the
       band has no ruled edge */
    linear-gradient(to top,
      rgba(255, 255, 0, 0) 0%,
      rgba(255, 255, 0, 0.2) 7%,
      rgba(255, 255, 0, 0.14) 42%,
      rgba(255, 255, 0, 0.2) 76%,
      rgba(255, 255, 0, 0.08) 93%,
      rgba(255, 255, 0, 0) 100%);
  /* the hover fills cannot carry a gradient — they transition their colour
     over 1200ms, which only background-color can do — so they sit at about
     the new stroke's average rather than at either end of it. */
  --accent-fill: rgba(255, 255, 0, 0.45);
}

/* "It should probably be a tiny bit longer than the text." The stroke runs
   past the last letter and lifts there, so the fade happens off the end of
   the word rather than across it. Negative margin of the same size, so the
   painted box grows and the layout does not move. */
.mark {
  padding-right: 0.45em;
  margin-right: -0.45em;
}
.border-b-2.border-accent {
  padding-right: 0.4em;
  /* these numerals carry mr-3 in the markup — 0.75rem of air before their
     label — so the pull-back has to keep it rather than replace it. */
  margin-right: calc(0.75rem - 0.4em);
}

/* Client, 2026-10-30: "'core areas' title is not aligned with the
   Psychiatry header."

   It was not aligned with anything. The labels have been centred since
   2026-10-13, and on the landing page every heading under them — Psychiatry,
   People, Library, The Essential Notes — sits on the column's left edge at
   40px while the label floated at 584. On the practice page the centred
   label happened to land at 585 against Psychiatry's 568, which is the
   worse case: seventeen pixels out reads as a mistake where being obviously
   centred would have read as a choice.

   So the labels go back to the column edge, where ONCE A MONTH already
   was — it was the lone exception to the centring, and now it is simply
   the rule. Every label on the site, both widths. */
.section-label {
  text-align: left;
}

/* Client, 2026-10-30, selecting the PHILOSOPHY label: "middle align."

   The labels went to the column edge so each one lines up with what it
   introduces — and that is exactly why this one is the exception. The
   vision statement under it is the only centred block on the site, so
   left-aligning the label pulled it away from its own section. Scoped to
   #vision, so the other four stay on the edge with their left-aligned
   content. */
#vision .section-label {
  text-align: center;
}

/* Client, 2026-10-30, on the landing page's "request initial consultation":
   "make this button go yellow when you click it — but click and hold, not
   on/off." The same behaviour the menu's booking box got earlier today, so
   it takes the same pressed state: the ink fill drops away, the wash comes
   through and the type goes back to ink, and it stays that way until
   booking.html takes over. The transition is cancelled while pressed —
   this button animates background-color over 300ms for its hover, and a
   fade is the on/off flicker the client is asking to be rid of. */
.cta-press:active,
.cta-press.is-pressed {
  background-color: transparent;
  background-image: var(--mark-wash);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: 0 0;
  color: var(--color-ink);
  transition: none;
  -webkit-tap-highlight-color: transparent;
}

/* The second half of the same fix. Even with focus no longer moving on a
   tap, anything that focuses one of these links by script would bring the
   browser's own ring back, and Safari's is a solid box around the word.
   A pointer-driven focus paints nothing; a keyboard one gets a deliberate
   ring in the site's own yellow instead of the UA default, so the
   indicator the accessibility pass asked for is stronger than it was, not
   weaker. */
.site-mobile-nav nav > a:focus:not(:focus-visible) {
  outline: none;
}
.site-mobile-nav nav > a:focus-visible {
  outline: 2px solid var(--color-accent-solid);
  outline-offset: 4px;
}

/* Client, 2026-10-30, selecting THE SPACE: "middle align all of these on
   the desktop version and leave the mobile version how it is."

   So the centring comes back, but only above 768px. The phone keeps the
   column edge it was given earlier today, and PHILOSOPHY keeps its own
   centring there because the statement under it is centred.

   ONCE A MONTH is untouched: it carries .section-label.text-paper/55,
   two classes against this rule's one, so its own left alignment still
   wins. That is the 2026-10-13 exception — it sits in the left cell of
   the newsletter's two-column band, not above a full-width section, so
   centring it would park it in the middle of a column rather than the
   page. */
@media (min-width: 48rem) {
  .section-label {
    text-align: center;
  }
}

/* Client, 2026-10-30: "make sure this is the same yellow as the other
   highlights."

   The pressed state already was. Hover was not: this button still ran the
   compiled `hover:bg-accent`, a flat rgba(255,255,0,0.45) field, while
   every mark on the site is the watercolour wash with its fade. On a
   209px button that flat even yellow reads as a different colour
   altogether.

   Hover now takes the same wash as the press, so the button has one
   yellow in both states and it is the site's. No transition: the 300ms
   fade it used to run only works on background-color, and a gradient
   cannot be carried by it — the press is already instant, so the two now
   match in motion as well. */
@media (hover: hover) {
  .cta-press:hover {
    background-color: transparent;
    background-image: var(--mark-wash);
    background-repeat: no-repeat;
    background-size: 100% 100%;
    background-position: 0 0;
    color: var(--color-ink);
    transition: none;
  }
}

/* Client, 2026-10-30: "same with this button, it looks grey-ish yellow."

   The newsletter's submit button is a paper rectangle sitting in the black
   band. On hover it ran `hover:bg-accent`, which *replaces* its white
   background with a 45%-opacity yellow — so the yellow was compositing
   over the near-black section behind it rather than over paper, and 45%
   lemon over #0a0a0a is a dark olive. That is the grey.

   It keeps its paper background now and takes the wash on top of it, so
   the yellow lands on white exactly as every mark on the site does.

   The booking form's submit button has the same flat-fill mismatch but
   sits on a paper page, so it never looked grey — only unlike the rest.
   It gets the same wash as the landing page's CTA. Both lose the 300ms
   colour fade for the same reason that one did: it cannot carry a
   gradient. */
@media (hover: hover) {
  button[type="submit"].bg-paper:hover {
    background-color: var(--color-paper);
    background-image: var(--mark-wash);
    background-repeat: no-repeat;
    background-size: 100% 100%;
    background-position: 0 0;
    color: var(--color-ink);
    transition: none;
  }
  button[type="submit"].bg-ink:hover {
    background-color: transparent;
    background-image: var(--mark-wash);
    background-repeat: no-repeat;
    background-size: 100% 100%;
    background-position: 0 0;
    color: var(--color-ink);
    transition: none;
  }
}

/* Client, 2026-10-30, selecting THE SPACE, both CORE AREAS and ADDITIONAL
   AREAS on a phone: "center align please in mobile site wide. All of these
   types of titles need to be centered apart from the philosophy header on
   the starting page."

   This reverses the move to the column edge from earlier today: the labels
   are centred at every width now, so the block above supplying `left` on a
   phone and `center` above 768px is superseded — both widths are centre.
   PHILOSOPHY was already centred and stays that way; it was named as the
   one not to touch, not as one to change.

   ONCE A MONTH was brought with them on the phone, on the reasoning that
   the newsletter band is a single stacked column there so the 2026-10-13
   exception no longer applied. The client looked at it and said "left
   align mobile wide", so that was wrong and it is reverted: the override
   is gone and its own two-class rule holds it left at every width, the
   only label that is never centred. */
.section-label {
  text-align: center;
}

/* Client, 2026-10-30: "font still quite big compared to the size of the
   popup — let's make the font smaller. And a bit more centered on the
   page. Both desktop and mobile."

   The box came down a tenth earlier today and the copy deliberately did
   not, so the type was left large for the rectangle it sits in. Both
   sizes now come down 15%: the two lines go 15.4px -> 13.1px and the
   actions 13.2px -> 11.2px. The card keeps its 423 x 193, so the air
   around the copy grows rather than the box shrinking again.

   Position: the panel has sat in the bottom-right corner above 640px
   since it was built, deliberately out of the page's way. It is still out
   of the way, but no longer in the corner — centred horizontally at every
   width, and lifted to 12vh so it floats clear of the bottom edge instead
   of hugging it. */
.notes-popup-text,
.notes-popup-sub {
  font-size: 0.818rem;
}
.notes-popup-join,
.notes-popup-dismiss {
  font-size: 0.7rem;
}
.notes-popup {
  bottom: max(1.5rem, 12vh);
}
@media (min-width: 640px) {
  .notes-popup {
    left: 1.5rem;
    justify-content: center;
  }
}

/* Client, 2026-10-30, with the Library card as the reference: "the
   hierarchy of the pop-up maybe more like here — small, grey, spaced 'A
   little room for thought.', then 'The Essential Notes.' with the current
   size and black. And then 'Get the Notes' a bit more spaced again (but
   black), leave 'Not now' unspaced and grey."

   So the two lines swap roles. What was the headline becomes the kicker
   and takes the size, colour and tracking the site already uses for
   "Blueprint 01" and "In preparation" — 0.6875rem at 0.2em in mist. The
   standfirst becomes the line that carries the weight: same size it has
   now, in ink. "Get the Notes" keeps its size and its ink, and takes
   0.14em — spaced, but less than the kicker, so the kicker stays the most
   letterspaced thing in the panel. "Not now" is already unspaced mist and
   is left alone. */
.notes-popup-text {
  font-size: 0.6875rem;
  letter-spacing: 0.2em;
  color: var(--color-mist);
}
.notes-popup-sub {
  color: var(--color-ink);
}
.notes-popup-join {
  letter-spacing: 0.14em;
}

/* One thing the hierarchy needs that was not asked for: the standfirst sat
   5.6px under the line above it, which was right when the two were the
   same size and read as a pair. Now that the first is a kicker, 5.6px
   makes it look like a wrapped line of the title rather than a label above
   it. 9.6px is enough to separate them without opening a gap. */
.notes-popup-sub {
  margin-top: 0.6rem;
}

/* Client, 2026-10-30: "the yellow marking is so good now! But let's make
   it a tiny bit longer still — the marking should exceed the text by 2-3
   letters. And a tiny bit more fade: starting a tiny bit stronger and
   fading almost completely towards the end."

   Two things, and the second one needed the stack rebuilt rather than
   nudged. The old tail could not go below about 0.23 because the baseline
   settle was a `to top` gradient — constant across the stroke, so it put
   a floor under every column of it. That layer is now a wide ellipse
   anchored at the bottom left instead, which keeps the ink-gathering-at-
   the-baseline look where the nib lands and lets it disappear with
   everything else. Every layer falls to zero by the right edge now.

   Composite runs about 0.78 at the entry, 0.12 by the last letter and
   0.06 at the very end of the overshoot, against 0.75 -> 0.23 before. */
:root {
  --mark-wash:
    /* where the nib lands: the heaviest pigment */
    radial-gradient(45% 140% at 7% 72%,
      rgba(255, 255, 0, 0.38) 0%,
      rgba(255, 255, 0, 0.15) 55%,
      rgba(255, 255, 0, 0) 80%),
    /* a second, lighter pool just after it, so the start is not one blob */
    radial-gradient(42% 120% at 26% 28%,
      rgba(255, 255, 0, 0.24) 0%,
      rgba(255, 255, 0, 0.08) 55%,
      rgba(255, 255, 0, 0) 78%),
    /* the stroke: full pressure at the left, lifting to nothing */
    linear-gradient(93deg,
      rgba(255, 255, 0, 0.46) 0%,
      rgba(255, 255, 0, 0.36) 14%,
      rgba(255, 255, 0, 0.26) 34%,
      rgba(255, 255, 0, 0.16) 54%,
      rgba(255, 255, 0, 0.09) 72%,
      rgba(255, 255, 0, 0.05) 86%,
      rgba(255, 255, 0, 0.03) 95%,
      rgba(255, 255, 0, 0) 100%),
    /* the return pass, off the other way, mottling where they overlap */
    linear-gradient(87deg,
      rgba(255, 255, 0, 0.22) 0%,
      rgba(255, 255, 0, 0.12) 18%,
      rgba(255, 255, 0, 0.17) 38%,
      rgba(255, 255, 0, 0.08) 58%,
      rgba(255, 255, 0, 0.03) 78%,
      rgba(255, 255, 0, 0.01) 92%,
      rgba(255, 255, 0, 0) 100%),
    /* the ink settling to the baseline — an ellipse at the bottom left, so
       it thins out along the stroke instead of running its whole length */
    radial-gradient(95% 75% at 14% 100%,
      rgba(255, 255, 0, 0.18) 0%,
      rgba(255, 255, 0, 0.07) 55%,
      rgba(255, 255, 0, 0) 82%);
}

/* "Exceed the text by 2-3 letters." A lowercase letter is about half an em
   on this face, so 1.3em is roughly two and a half of them. */
.mark {
  padding-right: 1.3em;
  margin-right: -1.3em;
}
.notes-popup-join {
  padding-right: 1.3em;
  margin-right: -1.3em;
}
/* The numerals are the exception. 01 02 03 have only 0.75rem of air before
   their label, so a 1.3em overshoot would paint into the word next to them.
   0.7em is as far as the stroke can run and still leave the gap readable. */
.border-b-2.border-accent {
  padding-right: 0.7em;
  margin-right: calc(0.75rem - 0.7em);
}

/* Client, 2026-10-30, repeating the request: longer still, and more fade.

   Measured on the live article titles first: the average character advance
   on this face is 0.54em, so the 1.3em tail was already 2.4 letters —
   inside the "2-3 letters" asked for, but at the bottom of it. It goes to
   1.62em, which is 3.0 letters exactly, the top of the range.

   And the fade deepens again: the nib pressure and the stroke's opening
   both come up, and the far stops come down, so the composite runs about
   0.83 at the entry and 0.01 at the very end — from a strong start to
   effectively nothing. */
:root {
  --mark-wash:
    radial-gradient(45% 140% at 7% 72%,
      rgba(255, 255, 0, 0.44) 0%,
      rgba(255, 255, 0, 0.17) 55%,
      rgba(255, 255, 0, 0) 80%),
    radial-gradient(42% 120% at 26% 28%,
      rgba(255, 255, 0, 0.26) 0%,
      rgba(255, 255, 0, 0.09) 55%,
      rgba(255, 255, 0, 0) 78%),
    linear-gradient(93deg,
      rgba(255, 255, 0, 0.54) 0%,
      rgba(255, 255, 0, 0.4) 14%,
      rgba(255, 255, 0, 0.27) 34%,
      rgba(255, 255, 0, 0.15) 54%,
      rgba(255, 255, 0, 0.075) 72%,
      rgba(255, 255, 0, 0.035) 86%,
      rgba(255, 255, 0, 0.015) 95%,
      rgba(255, 255, 0, 0) 100%),
    linear-gradient(87deg,
      rgba(255, 255, 0, 0.24) 0%,
      rgba(255, 255, 0, 0.13) 18%,
      rgba(255, 255, 0, 0.18) 38%,
      rgba(255, 255, 0, 0.07) 58%,
      rgba(255, 255, 0, 0.025) 78%,
      rgba(255, 255, 0, 0.005) 92%,
      rgba(255, 255, 0, 0) 100%),
    radial-gradient(95% 75% at 14% 100%,
      rgba(255, 255, 0, 0.2) 0%,
      rgba(255, 255, 0, 0.07) 55%,
      rgba(255, 255, 0, 0) 82%);
}
.mark,
.notes-popup-join {
  padding-right: 1.62em;
  margin-right: -1.62em;
}

/* Client, 2026-10-30, with two vertical marks drawn just inside the card's
   text on both sides: "move in tiny bit. Make font of overliner smaller
   and cta smaller, keep font size for 'The Essential Notes', so squish in
   the side of all text."

   The side padding goes 1.8rem -> 2.5rem, so every line starts and ends
   about 11px further in. The kicker and the two actions come down about a
   tenth to pay for it; the standfirst is the one size that does not move,
   so the step between it and everything around it widens. */
.notes-popup-card {
  padding: 1.575rem 2.5rem;
}
.notes-popup-text {
  font-size: 0.62rem;
}
.notes-popup-join,
.notes-popup-dismiss {
  font-size: 0.63rem;
}

/* Client, 2026-10-30: the highlight should finish two characters after
   every word — not three. At the measured 0.54em average advance on this
   face, two characters is 1.08em, so the prose marks come back from 1.62em.

   And "all words" includes 01 02 03, which have been the exception at
   0.7em because their 0.75rem gap to the label could not hold more. Two
   digits is 1.08em there as well, which is wider than that gap, so the
   gap grows: the stroke runs its full two characters and 0.5rem of clear
   space follows it before the label. The label sits about 9px further
   right than it did — the one layout change this needs, and the reason
   the numerals can now match everything else. The far end of the stroke
   is nearly transparent by then, so it does not read as marking the word
   beside it. */
.mark,
.notes-popup-join {
  padding-right: 1.08em;
  margin-right: -1.08em;
}
.border-b-2.border-accent {
  /* the numerals are tabular and narrower than the prose average — 5.87px
     against 9.84px — so two of them is 0.98em here, not 1.08em. */
  padding-right: 0.98em;
  margin-right: 0.5rem;
}

/* Client, 2026-10-30, with a crop of the header's current-page mark:
   "still not long enough."

   That one is the desktop navigation's own mark, and it was never given a
   tail — it had 2px, against the 16.9px that two of its characters come
   to. It is a fixed box sized to the link rather than a stroke over
   running text, which is why it was missed when the article titles, the
   numerals and the popup CTA were done.

   Two characters at its 8.45px advance is 1.1em. The padding is cancelled
   by an equal negative margin, so the spacing between nav items does not
   move; the stroke simply runs 17px into the 40px gap that follows. The
   rule is on .nav-mark rather than .nav-mark-active so the hover and the
   current-page states are the same shape. */
.nav-mark {
  padding-right: 1.1em;
  margin-right: -1.1em;
}

/* Client, 2026-10-30, with the ADHD title cropped: "longer!!! two
   characters after the word the highlight needs to go."

   The tail was already two characters — 20px against a 9.84px advance,
   measured. What was wrong is that it could not be seen. The fade runs in
   percentages of the painted box, and on a title 413px wide the two
   characters are the last 4.6% of it, where the old ramp had already
   fallen to about 0.02. So the stroke was finishing before the word did,
   and the overshoot was painted in nothing.

   The ramp now holds its weight through the word and spends the fade on
   the overshoot instead: about 0.81 at the entry, still 0.29 at the last
   letter, down to 0.12 at the end of the tail. It behaves on short marks
   too — on 01 the two characters are half the box, so the same curve
   gives that one a fade from 0.55 across its tail rather than a cliff. */
:root {
  --mark-wash:
    radial-gradient(45% 140% at 7% 72%,
      rgba(255, 255, 0, 0.38) 0%,
      rgba(255, 255, 0, 0.15) 55%,
      rgba(255, 255, 0, 0) 80%),
    radial-gradient(42% 120% at 26% 28%,
      rgba(255, 255, 0, 0.24) 0%,
      rgba(255, 255, 0, 0.09) 55%,
      rgba(255, 255, 0, 0) 78%),
    linear-gradient(93deg,
      rgba(255, 255, 0, 0.5) 0%,
      rgba(255, 255, 0, 0.44) 15%,
      rgba(255, 255, 0, 0.39) 35%,
      rgba(255, 255, 0, 0.34) 55%,
      rgba(255, 255, 0, 0.3) 75%,
      rgba(255, 255, 0, 0.28) 88%,
      rgba(255, 255, 0, 0.2) 96%,
      rgba(255, 255, 0, 0.09) 100%),
    linear-gradient(87deg,
      rgba(255, 255, 0, 0.22) 0%,
      rgba(255, 255, 0, 0.13) 20%,
      rgba(255, 255, 0, 0.18) 42%,
      rgba(255, 255, 0, 0.13) 65%,
      rgba(255, 255, 0, 0.11) 85%,
      rgba(255, 255, 0, 0.08) 96%,
      rgba(255, 255, 0, 0.03) 100%),
    radial-gradient(120% 75% at 14% 100%,
      rgba(255, 255, 0, 0.18) 0%,
      rgba(255, 255, 0, 0.06) 60%,
      rgba(255, 255, 0, 0) 95%);
}

/* Client, 2026-10-30, selecting CORE AREAS on the practice page: "core
   areas need to align with the Psychiatry title."

   On this page the first card is image-left, text-right, so Psychiatry
   does not sit on the column edge — it starts where the card's text
   column does. Measured: the row is 1285 wide with an 80px gap and a 2/5
   image, so the text column begins 0.4 x (W - 80) + 80 = 40% + 48px in
   from the row's left. The label takes exactly that indent and goes
   left-aligned inside it, which lands it on 602, Psychiatry's own ink
   edge.

   Expressed in the row's own terms rather than as a fixed number, so it
   follows the card if the window changes. Above 768px only: below that
   the card stacks and Psychiatry returns to the column edge, so the label
   keeps the centring it has there. Scoped by .label-step-down, which is
   on this one wrapper and no other. */
@media (min-width: 48rem) {
  main .reveal.label-step-down .section-label {
    text-align: left;
    padding-left: calc(40% + 48px);
  }
}

/* Client, 2026-10-30: "a little more fade now. So extend the highlight a
   slight bit and go from 100 percent to 0 percent opacity."

   Taken literally: the stroke now starts at a solid 1.0 where the nib
   lands and reaches a true 0 at the end — the main pass carries the full
   range itself, so the composite cannot sit above or below it at either
   extreme. The tail goes from two characters to two and a half.

   The shape matters as much as the endpoints. A straight 1.0-to-0 ramp
   would put the end of a long title back in the invisible zone, which was
   the problem two rounds ago: on a 413px title the tail is only the last
   5% of the painted box. So the pressure eases off gradually through the
   word — 1.0, 0.62 by a third, 0.42 by two thirds, 0.35 at 88% — and the
   pen lifts over the final tenth, 0.21 at the last letter down to nothing
   at the end of the overshoot. Short marks get the same curve: on the
   nav's "Library" the word ends at 78%, so it reads 0.38 there and fades
   from that. */
:root {
  --mark-wash:
    radial-gradient(45% 140% at 7% 72%,
      rgba(255, 255, 0, 0.26) 0%,
      rgba(255, 255, 0, 0.1) 55%,
      rgba(255, 255, 0, 0) 80%),
    radial-gradient(42% 120% at 26% 28%,
      rgba(255, 255, 0, 0.16) 0%,
      rgba(255, 255, 0, 0.06) 55%,
      rgba(255, 255, 0, 0) 78%),
    linear-gradient(93deg,
      rgba(255, 255, 0, 1) 0%,
      rgba(255, 255, 0, 0.62) 12%,
      rgba(255, 255, 0, 0.45) 30%,
      rgba(255, 255, 0, 0.38) 55%,
      rgba(255, 255, 0, 0.34) 78%,
      rgba(255, 255, 0, 0.3) 88%,
      rgba(255, 255, 0, 0.16) 96%,
      rgba(255, 255, 0, 0) 100%),
    linear-gradient(87deg,
      rgba(255, 255, 0, 0.16) 0%,
      rgba(255, 255, 0, 0.09) 20%,
      rgba(255, 255, 0, 0.13) 42%,
      rgba(255, 255, 0, 0.09) 65%,
      rgba(255, 255, 0, 0.07) 85%,
      rgba(255, 255, 0, 0.03) 96%,
      rgba(255, 255, 0, 0) 100%),
    radial-gradient(120% 75% at 14% 100%,
      rgba(255, 255, 0, 0.12) 0%,
      rgba(255, 255, 0, 0.04) 60%,
      rgba(255, 255, 0, 0) 92%);
}

/* Two and a half characters, at each mark's own measured advance. */
.mark,
.notes-popup-join {
  padding-right: 1.36em;
  margin-right: -1.36em;
}
.border-b-2.border-accent {
  padding-right: 1.22em;
  margin-right: 0.5rem;
}
.nav-mark {
  padding-right: 1.38em;
  margin-right: -1.38em;
}

/* Client, 2026-10-30: "we had this nice watercolour fade thing and now it
   is gone, can you bring it back."

   Correct, and it was my doing. To get a clean 100%-to-0% ramp I turned
   the texture layers right down so they could not lift the ends off the
   envelope — the pools from 0.42 to 0.26, the return pass from 0.22 to a
   monotone 0.16, the baseline settle from 0.18 to 0.12. What was left was
   one smooth gradient: the right endpoints, none of the paper.

   The texture comes back without losing the envelope. The main pass still
   carries the full 1.0-to-0 on its own, but its middle is pulled down so
   the other layers have room to show through rather than being drowned.
   The return pass alternates again — 0.26, 0.10, 0.24, 0.08, 0.20 — and
   because it runs at 87deg against the main pass's 93deg, the peaks never
   line up and the density wobbles as it descends instead of sliding. Both
   pools and the baseline ellipse are back at full strength and all of
   them still reach zero before the right edge, so the end is untouched.

   Composite: 1.00, 0.82, 0.69, 0.44, 0.41, 0.27, 0.12, 0 — a descent with
   texture in it rather than a straight line. */
:root {
  --mark-wash:
    /* pigment pooling where the nib lands */
    radial-gradient(45% 140% at 7% 72%,
      rgba(255, 255, 0, 0.42) 0%,
      rgba(255, 255, 0, 0.16) 55%,
      rgba(255, 255, 0, 0) 80%),
    /* a second pool, higher and a third along, so the start is not a blob */
    radial-gradient(40% 115% at 30% 25%,
      rgba(255, 255, 0, 0.28) 0%,
      rgba(255, 255, 0, 0.1) 55%,
      rgba(255, 255, 0, 0) 78%),
    /* the stroke: full pressure to nothing, the envelope everything sits in */
    linear-gradient(93deg,
      rgba(255, 255, 0, 1) 0%,
      rgba(255, 255, 0, 0.55) 12%,
      rgba(255, 255, 0, 0.34) 30%,
      rgba(255, 255, 0, 0.26) 55%,
      rgba(255, 255, 0, 0.22) 78%,
      rgba(255, 255, 0, 0.19) 88%,
      rgba(255, 255, 0, 0.1) 96%,
      rgba(255, 255, 0, 0) 100%),
    /* the return pass, off-angle and alternating — this is the mottling */
    linear-gradient(87deg,
      rgba(255, 255, 0, 0.26) 0%,
      rgba(255, 255, 0, 0.1) 16%,
      rgba(255, 255, 0, 0.24) 34%,
      rgba(255, 255, 0, 0.08) 52%,
      rgba(255, 255, 0, 0.2) 68%,
      rgba(255, 255, 0, 0.07) 82%,
      rgba(255, 255, 0, 0.1) 91%,
      rgba(255, 255, 0, 0.02) 97%,
      rgba(255, 255, 0, 0) 100%),
    /* the ink settling to the baseline where the stroke is still wet */
    radial-gradient(120% 70% at 16% 100%,
      rgba(255, 255, 0, 0.2) 0%,
      rgba(255, 255, 0, 0.07) 60%,
      rgba(255, 255, 0, 0) 92%);
}

/* Client, 2026-10-31, with a photograph of a real highlighter on paper:
   "make the colour and texture exactly like this. Sample the colour and
   apply it site wide, then analyse the stroke and apply it site wide."

   Sampled from the photo (30,665 ink pixels against 42,411 of paper):

   COLOUR. Paper in the shot reads (177,179,173) — under-exposed — and the
   densest ink (200,233,103). White-balancing against that paper clips red
   and green, because highlighter ink fluoresces: it puts out more light
   than it transmits. So the hue and saturation are what carry over, and
   they are not what the site has been using. The ink is hue 75.2 deg at
   0.56 saturation — a chartreuse — where every mark here has been pure
   #ffff00, hue 60 at full saturation. At full value that is #dbff71, and
   that is now the ink colour everywhere.

   ACROSS THE STROKE. Nine vertical cuts: the edge sits at 0.75 of the
   centre's density on average, never below 0.48. A real highlighter is
   nearly flat across its width. The wash had been feathering top and
   bottom to nothing, which is why it read as a soft gradient band rather
   than a pen stroke, so the across-profile is now almost uniform.

   ALONG THE STROKE. Three horizontal cuts, sampled in tenths:
     0.28 0.35 0.36 0.38 0.26 0.25 0.31 0.25 0.29 0.24
     0.36 0.37 0.27 —    0.22 0.32 0.26 0.30 0.29 0.27
     0.50 0.51 0.44 0.38 0.42 0.39 0.37 0.37 0.37 0.33
   Two things fall out. It starts denser and settles — about a third down
   over its length, not to nothing. And it never descends smoothly: every
   row wobbles up and down by around 20% as it goes. That wobble is the
   texture, and it is why the mottling layer alternates rather than ramps.

   The body of the stroke is therefore much flatter than it was, holding
   0.5 to 0.75 where the photo's typical density maps to 0.58 — and the
   fade to nothing is kept for the last tenth, which is the pen lifting,
   and what was asked for over the past few rounds.

   Corrected after the first render. The body had been calibrated as if the
   new ink absorbed like the old one, and it does not: #ffff00 carries no
   blue at all, so at a given alpha it takes the paper's blue all the way
   down, while this chartreuse keeps 113 of it and lands far paler at the
   same alpha. The photo's ink leaves blue at 60% of paper, which over
   #fafafa needs 0.73, not the 0.58 the first pass gave. The body stops are
   raised to hold that. */
:root {
  --color-accent: rgba(241, 255, 100, 0.7);
  --color-accent-solid: #f1ff64;
  --accent-fill: rgba(241, 255, 100, 0.55);
  --mark-wash:
    /* pigment pooling where the nib lands */
    radial-gradient(50% 150% at 8% 60%,
      rgba(241, 255, 100, 0.3) 0%,
      rgba(241, 255, 100, 0.12) 60%,
      rgba(241, 255, 100, 0) 85%),
    /* a second pool a third along */
    radial-gradient(45% 130% at 32% 40%,
      rgba(241, 255, 100, 0.2) 0%,
      rgba(241, 255, 100, 0.07) 60%,
      rgba(241, 255, 100, 0) 82%),
    /* the stroke: dense at the nib, settling across the body, lifting at
       the end — the shape the three horizontal cuts describe */
    linear-gradient(93deg,
      rgba(241, 255, 100, 1) 0%,
      rgba(241, 255, 100, 0.82) 10%,
      rgba(241, 255, 100, 0.7) 28%,
      rgba(241, 255, 100, 0.64) 50%,
      rgba(241, 255, 100, 0.6) 72%,
      rgba(241, 255, 100, 0.52) 86%,
      rgba(241, 255, 100, 0.28) 95%,
      rgba(241, 255, 100, 0) 100%),
    /* the wobble: alternating, and off-angle so its peaks never line up
       with the pass above */
    linear-gradient(87deg,
      rgba(241, 255, 100, 0.22) 0%,
      rgba(241, 255, 100, 0.08) 15%,
      rgba(241, 255, 100, 0.2) 32%,
      rgba(241, 255, 100, 0.07) 50%,
      rgba(241, 255, 100, 0.18) 66%,
      rgba(241, 255, 100, 0.06) 80%,
      rgba(241, 255, 100, 0.12) 90%,
      rgba(241, 255, 100, 0.02) 97%,
      rgba(241, 255, 100, 0) 100%),
    /* body weight. A 160% vertical radius means it barely varies over the
       band's height — flat across, as the cuts showed — while still
       falling away along the stroke so the end can reach nothing. */
    radial-gradient(130% 160% at 18% 50%,
      rgba(241, 255, 100, 0.18) 0%,
      rgba(241, 255, 100, 0.07) 55%,
      rgba(241, 255, 100, 0) 88%);
}

/* Client, 2026-10-31: "make it a bit more stroke like, like what we had
   originally — watercolour, with no definite line for the ending."

   The photo-driven version went rectangular, and the reason is structural:
   a linear-gradient is uniform along its perpendicular, so a horizontal
   one paints a hard top and bottom edge at the box, however softly it
   fades left to right. Background layers composite source-over, so no
   later layer can subtract that edge back off. Every straight line in the
   mark came from those two passes.

   So the stroke is no longer a gradient with texture added — it is built
   out of seven overlapping ellipses laid along its length, which is what
   a nib actually leaves. Each one feathers in every direction, so there
   is no straight boundary anywhere: not at the top, not at the bottom,
   not at either end. Their overlaps do the mottling, and their alternating
   vertical centres (52, 44, 56, 46, 54, 47, 53) keep the band from
   reading as a ruled strip.

   Modelled before it was written, sampled across the box:
     along, mid height:  0.66 0.93 0.74 0.72 0.77 0.66 0.66 0.71 0.59
                         0.58 0.66 0.55 0.52 0.58 0.47 0.43 0.43 0.31
                         0.27 0.17 0.06
     across:             edge sits at 0.35-0.57 of centre, so the long
                         edges are soft rather than cut
   It enters soft at 0.66, peaks at 0.93 where the nib lands, wobbles
   through the body instead of descending evenly, and leaves at 0.06 —
   no line at the end, nor at the start. */
:root {
  --mark-wash:
    radial-gradient(17% 102% at 4.5% 52%,
      rgba(241, 255, 100, 0.95) 0%,
      rgba(241, 255, 100, 0.333) 55%,
      rgba(241, 255, 100, 0) 100%),
    radial-gradient(20% 92% at 19% 44%,
      rgba(241, 255, 100, 0.78) 0%,
      rgba(241, 255, 100, 0.273) 55%,
      rgba(241, 255, 100, 0) 100%),
    radial-gradient(21% 105% at 34% 56%,
      rgba(241, 255, 100, 0.68) 0%,
      rgba(241, 255, 100, 0.238) 55%,
      rgba(241, 255, 100, 0) 100%),
    radial-gradient(21% 88% at 50% 46%,
      rgba(241, 255, 100, 0.6) 0%,
      rgba(241, 255, 100, 0.21) 55%,
      rgba(241, 255, 100, 0) 100%),
    radial-gradient(21% 98% at 65% 54%,
      rgba(241, 255, 100, 0.5) 0%,
      rgba(241, 255, 100, 0.175) 55%,
      rgba(241, 255, 100, 0) 100%),
    radial-gradient(19% 86% at 79% 47%,
      rgba(241, 255, 100, 0.36) 0%,
      rgba(241, 255, 100, 0.126) 55%,
      rgba(241, 255, 100, 0) 100%),
    radial-gradient(15% 74% at 91% 53%,
      rgba(241, 255, 100, 0.19) 0%,
      rgba(241, 255, 100, 0.067) 55%,
      rgba(241, 255, 100, 0) 100%);
}

/* Client, 2026-10-31: "the popup needs to be in the bottom right corner of
   the desktop version. Also can you make it 30% more transparent."

   The corner is where it started; it was moved to the centre and lifted to
   12vh yesterday on the "a bit more centered" note. Desktop goes back: the
   wrapper is right-anchored again and sits 1.5rem off the bottom. The
   phone keeps the centring and the lift, which is not what was asked to
   change.

   The card's paper was 97% opaque; 30% more transparent is 68%. The 8px
   backdrop blur it already carries does more work at that level, which is
   what keeps the copy readable over an image.

   The max-width line is a guard, not a change. Below 768px the card is
   capped at 90% of its container for the phone, but the right-anchored
   wrapper shrink-wraps to the card from 640px up — so between those two
   widths the percentage would resolve against the card's own width and
   take a second 10% off it, the same trap that turned 423 into 381 last
   time. Above 640 the cap goes back to 100%. */
@media (min-width: 640px) {
  .notes-popup {
    left: auto;
    justify-content: flex-end;
    bottom: 1.5rem;
  }
  .notes-popup-card {
    max-width: 100%;
  }
}
.notes-popup-card {
  background: #fafafaad;
  background: color-mix(in oklab, var(--color-paper) 68%, transparent);
}

/* Client, 2026-11-03: "the marking effect, especially on the phone, is
   looking greenish at the moment — can we make it a little bit more yellow
   but still this highlighter hue."

   The ink sampled from the highlighter photo was hue 75.2 deg, and over the
   page it holds that hue at every density — 75 deg at full strength, still
   75 deg at 0.3 — so the thin end of the stroke reads as green as the thick
   end. Phone panels push saturated yellow-greens further towards green
   still, which is where it showed most.

   The ink moves to rgb(241, 255, 100), hue 65.4 deg at 0.61 saturation:
   five degrees off pure yellow rather than fifteen, and slightly more
   saturated so it keeps the fluorescent bite rather than going lemon-pale.
   Every rgba in the stroke, the accent, the hover fill and the focus ring
   changed in place; the stroke's shape, densities and tails are untouched.
   Over the paper it now composites to hue 65 at full strength and 66 at
   0.3, against 75 before. */

/* Client, 2026-11-03, on the practice page: "make sure these are all
   aligned from the left side."

   The boxes already were — heading and both paragraphs start at the same
   pixel. The difference is the face's left side bearing: the empty space
   each letter carries before its ink, which scales with the type. Measured
   by rendering the glyphs at 6x:

     EN  heading "O"  2.00px in   paragraphs "W" 0.17px, "O" 0.50px
     DE  heading "U"  3.67px in   paragraphs "W" 0.17px, "G" 0.50px

   So the heading is pulled left by its own excess over the paragraphs,
   in em so it holds at every breakpoint. German needs nearly twice the
   correction because its heading opens on an upright, which this face
   insets further than a round letter. The remaining 0.33px between the
   two paragraphs is below what a screen can show, so they are left as
   they are. One class, used only on this heading. */
.optical-flush {
  text-indent: -0.04em;
}
html[lang="de"] .optical-flush {
  text-indent: -0.077em;
}

/* Client, 2026-11-03: "also make sure these are aligned" — CORE AREAS
   over the Psychiatry heading on the practice page.

   Boxes were already identical (568px at 1280 wide). Measured ink edges:
     label "C" / "S"          568.38
     paragraph "S" / "F"      568.63 / 569.25
     heading "P"              570.13
   The heading is the outlier: P is an upright, and this face sets
   uprights 0.088em in from their box, which at 24px is 2.13px against the
   label's 0.38px. "Psychiatrie" opens on the same letter, so one value
   covers both languages. The heading is pulled left by the difference,
   in em so it holds at every size. */
.optical-flush-upright {
  text-indent: -0.073em;
}

/* Client, 2026-11-03: "also make sure these are aligned — additional and
   diagnostics." The same treatment CORE AREAS got over Psychiatry.

   Above 768px the explorer is a 0.8fr / 1.2fr grid with a 4rem gap, so
   the detail panel starts 0.4 x (W - 4rem) + 4rem = 40% + 2.4rem in from
   the row — 558.4px at 1280 wide, the panel's own measured edge. The
   label takes that indent and goes left-aligned inside it, so it tracks
   the panel at any width. Below 768px the explorer stacks and the label
   keeps the centring the phone has.

   The four panels swap into that same spot, so each heading gets the
   side-bearing correction for its own first letter, in both languages:
     Diagnostics / Diagnostik            D / D   upright
     Psychological coaching / Psycho...  P / P   upright
     Couples therapy / Paartherapie      C / P   round, then upright
     Supervision / Supervision           S / S   round
   Couples therapy happens to change letter class between languages in
   exactly the way "Our practice" / "Unsere Praxis" does, so it shares
   that class. Supervision opens on a round letter in both and gets one
   value that does not change with the language. */
@media (min-width: 48rem) {
  main .reveal:has(+ .offer-explorer) .section-label {
    text-align: left;
    padding-left: calc(40% + 2.4rem);
  }
}
.optical-flush-round {
  text-indent: -0.044em;
}

/* Booking form, sent in the background (2026-11-03).
   .form-trap hides the spam honeypot from people and screen readers — bots
   still see and fill it. The status line collapses while it has nothing to
   say, and the button shows it's busy while the enquiry is on its way. */
.form-trap {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
[data-booking-status]:empty {
  margin-top: 0;
}
form button[type="submit"]:disabled {
  cursor: progress;
}

/* Client, 2026-11-03, with a screenshot of the open service menu: "can we
   change this drop down menu to something more classy and editorial like
   the rest of the website".

   The open menu was the operating system's — rounded panel, blue bar,
   system font — which CSS cannot style. site.js (6b, ServiceSelect) now
   draws its own field and list over the hidden <select>; this is how they
   look.

   Closed, it is just the current choice and a hairline chevron beside
   it. Open, the list floats just under it on
   the same frosted paper as the notes popup, only as wide as its words
   (client, 2026-11-03: "the menu is too wide ... inline with the what are
   you looking for?"). The glass reaches out to the left so that the
   choices start exactly under the caption and the current value. The choices settle in one after
   another. Pointing at one, or arrowing to it, draws the site's
   highlighter stroke through the word; the current choice carries a short
   rule in the margin, in place of the system's tick. The diagnostics
   group is headed the way section labels are, small and spaced, and its
   three choices sit a step in. */
.svc {
  position: relative;
  /* how far the glass reaches out past the left of the field, so the
     choices themselves start on the same line as the caption above */
  --svc-inset: 1.5rem;
}
.svc-native {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  clip-path: inset(50%);
}
/* Client, 2026-11-03: "get rid of the big long line and move the arrow
   closer to the not sure yet". No underline, and the field is only as wide
   as its words, with the chevron just after them — so the click target is
   the words themselves rather than an invisible full-width strip. */
.svc-trigger {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.65rem;
  width: fit-content;
  max-width: 100%;
  border-bottom: 0;
  text-align: left;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}
/* With no line left to darken, keyboard focus is shown with the
   highlighter under the value instead. */
.svc-value {
  padding: 0.08em 1.36em 0.08em 0.22em;
  margin: -0.08em -1.36em -0.08em -0.22em;
  border-radius: 0.6em 0.3em 0.55em 0.25em / 0.4em 0.7em 0.3em 0.6em;
  background-repeat: no-repeat;
  background-size: 100% 100%;
}
.svc-trigger:focus-visible .svc-value {
  background-image: var(--mark-wash);
}
.svc-chevron {
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.45s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.svc-trigger[aria-expanded="true"] .svc-chevron {
  transform: translateY(2px) rotate(-135deg);
}
.svc-list {
  position: absolute;
  top: calc(100% + 0.6rem);
  left: calc(-1 * var(--svc-inset));
  z-index: 30;
  width: max-content;
  max-width: calc(100% + var(--svc-inset));
  padding: 0.7rem 0 0.85rem;
  /* the notes popup's glass: 68% paper, the page blurred behind it, and a
     soft shadow for an edge instead of a rule (client, 2026-11-03: "lets
     make it transparent like the pop up") */
  background: #fafafaad;
  background: color-mix(in oklab, var(--color-paper) 68%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 2px 28px rgba(10, 10, 10, 0.1);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition:
    opacity 0.25s ease,
    transform 0.4s cubic-bezier(0.2, 0.7, 0.2, 1),
    visibility 0s linear 0.4s;
}
.svc.is-open .svc-list {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition:
    opacity 0.3s ease,
    transform 0.45s cubic-bezier(0.2, 0.7, 0.2, 1),
    visibility 0s;
}
.svc-option,
.svc-group {
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.svc.is-open .svc-option,
.svc.is-open .svc-group {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.4s ease calc(var(--i, 0) * 28ms + 60ms),
    transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) calc(var(--i, 0) * 28ms + 60ms);
}
.svc-option {
  position: relative;
  /* the right side leaves room for the highlighter's tail */
  padding: 0.5rem 2rem 0.5rem var(--svc-inset);
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--color-ink);
  cursor: pointer;
}
.svc-grouped .svc-option {
  padding-left: calc(var(--svc-inset) + 1rem);
}
.svc-option[aria-selected="true"]::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0.45rem;
  width: 0.6rem;
  height: 1px;
  background: currentColor;
}
/* the same stroke and two-and-a-half-character tail as .mark */
.svc-text {
  padding: 0.08em 1.36em 0.08em 0.22em;
  margin: 0 -1.36em 0 -0.22em;
  border-radius: 0.6em 0.3em 0.55em 0.25em / 0.4em 0.7em 0.3em 0.6em;
  background-repeat: no-repeat;
  background-size: 100% 100%;
}
.svc-option.is-active .svc-text {
  background-image: var(--mark-wash);
}
.svc-group {
  padding: 1rem 2rem 0.35rem var(--svc-inset);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-mist);
}
@media (max-width: 47.99rem) {
  /* the phone's gutter is 24px, so the glass reaches out less — and
     there is no room left in it for the margin rule. Nothing is lost:
     with no pointer to move it, the highlight opens on the current
     choice and stays there until a tap. */
  .svc {
    --svc-inset: 1rem;
  }
  .svc-trigger,
  .svc-option {
    font-size: 16px;
  }
  .svc-option {
    padding-block: 0.6rem;
  }
  .svc-option[aria-selected="true"]::before {
    content: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .svc-list,
  .svc.is-open .svc-list,
  .svc-option,
  .svc-group,
  .svc.is-open .svc-option,
  .svc.is-open .svc-group,
  .svc-chevron {
    transition: none;
  }
}

/* Client copy, 2026-11-04, for after a newsletter sign-up — "Almost there. /
   Please check your inbox to confirm your subscription." — with: "this is
   what pops up, similar to the pop ups we made."

   So it IS that popup: site.js builds a second .notes-popup with the same
   card, place, glass and close button, and only the words differ. The
   headline takes the nudge's black line (.notes-popup-sub); the sentence
   under it is quieter, mist and unspaced, like the nudge's "Not now". The
   nudge's 193px minimum height was set for its three rows; two lines don't
   need it. The same card says "welcome" after the confirmation link, and,
   since 2026-11-05, "Thank you." after a booking enquiry. */
.notes-popup--confirm .notes-popup-card {
  min-height: 0;
}
.notes-popup--confirm .notes-popup-sub {
  margin-top: 0;
  padding-right: 1rem;
}
.notes-popup-note {
  margin-top: 0.6rem;
  padding-right: 1rem;
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--color-mist);
  text-wrap: pretty;
}

/* Client, 2026-11-04: "make the pop up fade in slower by 40 percent."
   600ms → 840ms. Set on the shown state, so it is the arrival that slows —
   fade and rise together — while closing keeps its 600ms. Both popups share
   this card, the notes nudge and the newsletter confirmation, so they still
   arrive alike. Reduced motion is unaffected: that rule removes the
   transition altogether. */
.notes-popup.is-shown .notes-popup-card {
  transition-duration: 840ms;
}

/* Client, 2026-11-05: "a glitch where it shows the flower picture when you
   load into the website on mobile" and "a fade in when the website loads with
   the video so it feels smoother as it's loading."

   The flower still lies under the film for return visits (.hero-sealed). On a
   first visit it was drawn too, and a phone paints a picture long before the
   film has a frame, so the flowers flashed up first. It now only appears on a
   return. A first visit opens on paper, and the film fades in over it once it
   is actually moving (initHeroFilm in site.js adds .is-ready). */
body:not(.hero-sealed) img.splash-media {
  display: none;
}
body.has-splash:not(.hero-sealed) video.splash-media {
  opacity: 0;
  transition: opacity 1.6s ease;
}
body.has-splash:not(.hero-sealed) video.splash-media.is-ready {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  body.has-splash:not(.hero-sealed) video.splash-media {
    opacity: 1;
    transition: none;
  }
}


/* Client, 2026-11-05, practice page: "keep the section labels centred, align
   the text with them." Supersedes the two label-step-down / offer-explorer
   label rules of 2026-10-30 and 2026-11-03: CORE AREAS and ADDITIONAL AREAS
   are centred again, and the content beneath starts at the label's first
   letter instead. initLabelAlign in site.js measures that letter into
   --label-x and adds .label-aligned to the row; without it (no script) the
   labels are simply centred and the content stays where it was.

   Psychiatry's card keeps its picture at the width it had (40% of the row,
   less its share of the old 80px gap) so it still matches the Psychotherapy
   picture beneath; only the gap gives way. The explorer keeps its 4rem gap
   and its index column gives way, but only down to the 16rem the longest
   tab needs ("Psychological coaching" 219px, "Psychologisches Coaching"
   247px); below that, on a tablet, the gap gives way instead, to 1.5rem. */
@media (min-width: 48rem) {
  main .reveal.label-step-down .section-label,
  main .reveal:has(+ .offer-explorer) .section-label {
    text-align: center;
    padding-left: 0;
  }
  .label-aligned > .label-step-down + div > article:first-child > div > :first-child {
    flex: 0 0 calc(40% - 2rem);
  }
  .label-aligned > .label-step-down + div > article:first-child > div > :last-child {
    flex: 1 1 0;
    min-width: 0;
  }
  .label-aligned > .label-step-down + div > article:first-child > div {
    column-gap: calc(var(--label-x) - 40% + 2rem);
  }
  .label-aligned > .offer-explorer.is-enhanced {
    --index-w: max(calc(var(--label-x) - 4rem), min(16rem, calc(var(--label-x) - 1.5rem)));
    grid-template-columns: var(--index-w) minmax(0, 1fr);
    column-gap: calc(var(--label-x) - var(--index-w));
  }
}

/* Client, 2026-11-05: "instead of a drop down lets make it a pop up
   question. english/german, how would you like the notes." The nudge's card
   with the two languages as its actions: the spacing and size of "Get the
   Notes", in ink, and the same highlighter when pointed at or focused. Two
   lines are all it holds, so it drops the nudge's minimum height. */
.notes-popup--ask .notes-popup-card {
  min-height: 0;
}
.notes-popup--ask .notes-popup-actions {
  justify-content: flex-start;
  gap: 2.25rem;
}
.notes-popup-choice {
  appearance: none;
  background: none no-repeat;
  border: 0;
  margin: 0 -1.3em 0 0;
  padding: 0 1.3em 0.15em 0;
  font-family: inherit;
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  color: var(--color-ink);
  cursor: pointer;
  background-position: 0 calc(100% - var(--mark-lift));
  background-size: 100% var(--mark-band);
}
.notes-popup-choice:focus {
  outline: none;
}
.notes-popup-choice:focus-visible,
.notes-popup-choice:active {
  background-image: var(--mark-wash);
}
@media (hover: hover) {
  .notes-popup-choice:hover {
    background-image: var(--mark-wash);
  }
}

/* The newsletter landing page (letter.html) is black from edge to edge,
   and the popups' frosted paper turns grey over it. There the cards are
   solid paper, so the language question and the welcome read as they do
   everywhere else. */
body:has(.newsletter-landing) .notes-popup-card {
  background: var(--color-paper);
}

/* Client, 2026-11-05: the landing page is "a full black page" — no menu bar,
   no footer, the whole screen held by the sign-up, with "explore essential
   mind" and the language switch on one quiet line at the foot. */
.newsletter-page .newsletter-landing {
  min-height: 100vh;
  min-height: 100svh;
}
.newsletter-explore {
  /* unspaced (client, 2026-11-06: "get rid of the double spacing") */
  letter-spacing: 0;
  color: rgba(250, 250, 250, 0.55);
  transition: color 0.3s;
}
.newsletter-explore:hover,
.newsletter-explore:focus-visible {
  color: var(--color-paper);
}
.newsletter-landing .lang-switch {
  margin-left: 0;
}
.newsletter-landing .lang-option {
  color: rgba(250, 250, 250, 0.45);
}
.newsletter-landing .lang-option.is-active,
.newsletter-landing .lang-option:hover,
.newsletter-landing .lang-option:focus-visible {
  color: var(--color-paper);
}
.newsletter-landing .lang-sep {
  color: rgba(250, 250, 250, 0.25);
}

/* "explore essential mind" centred (client, 2026-11-05); the language
   switch keeps the right edge, out of the flow so it can't push the link
   off centre. */
.newsletter-foot .lang-switch {
  position: absolute;
  right: 1.5rem;
}
@media (min-width: 48rem) {
  .newsletter-foot .lang-switch {
    right: 2.5rem;
  }
}

/* On a phone the German "essential mind entdecken" runs into the switch, so
   there the two stack, both centred. */
@media (max-width: 47.99rem) {
  .newsletter-foot {
    flex-direction: column;
    gap: 1.25rem;
  }
  .newsletter-foot .lang-switch {
    position: static;
  }
}

/* Client, 2026-11-06, on /newsletter: "make the font tiny bit smaller in
   general on that page and have everything a bit more centered." About a
   tenth off every size, and the two columns drawn into a narrower block
   (56rem instead of the site's 72rem) so the composition gathers towards
   the middle of the screen instead of reaching for its edges. */
.newsletter-page .newsletter-landing .grid {
  max-width: 56rem;
}
.newsletter-page .newsletter-landing .section-label {
  font-size: calc(var(--text-xs) * 0.7);
}
.newsletter-page #notes p.font-serif {
  font-size: calc(var(--text-base) * var(--type-body) * 0.9);
}
.newsletter-page .newsletter-landing input[type="email"] {
  font-size: 0.8125rem;
}
.newsletter-page .newsletter-landing button[type="submit"] {
  font-size: 0.625rem;
}
.newsletter-page .newsletter-landing [aria-live] {
  font-size: 0.6875rem;
}
@media (max-width: 47.99rem) {
  .newsletter-page main h1.h1-fit.text-5xl {
    font-size: min(calc((var(--text-5xl) - 1pt) * 0.9), calc((9.5vw - 5px) * 0.9));
  }
}
@media (min-width: 48rem) {
  .newsletter-page .newsletter-landing .grid {
    column-gap: 4rem;
  }
  .newsletter-page main h1.text-5xl {
    font-size: 2.55rem;
  }
  .newsletter-page #notes p.font-serif {
    font-size: calc(var(--text-lg) * var(--type-body) * 0.9);
  }
  /* the narrower block left the title column a little short for it: the
     text side takes a touch more of the width, and the title keeps to one
     line */
  .newsletter-page .newsletter-landing .grid {
    grid-template-columns: 1.15fr 0.85fr;
  }
  .newsletter-page main h1.text-5xl {
    white-space: nowrap;
  }
}

/* Client, 2026-11-06: "maybe the language selector at the top right so it
   fits with the website." Laid over the top of the page in a strip the size
   of the site's menu bar — full width, 82px tall on a phone and 91px from
   768px up, the same side padding — and pinned to its right, so EN | DE
   lands exactly where it sits on every other page. Laid over, not in the
   flow, so the sign-up stays centred on the screen. The foot keeps only
   the link. */
.newsletter-landing {
  position: relative;
}
.newsletter-page .newsletter-top {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  max-width: none;
  height: 82px;
  justify-content: flex-end;
  padding-inline: 1.5rem;
}
@media (min-width: 48rem) {
  .newsletter-page .newsletter-top {
    height: 91px;
    padding-inline: 2.5rem;
  }
}

/* Client, 2026-11-06: "e x p l o r e  essential mind / essential mind
   e n t d e c k e n" — only the verb is spaced, the name stays as it is.
   German puts the verb last, so the link carries both orders and shows the
   one for the language on screen. */
.newsletter-explore .explore-verb {
  letter-spacing: 0.25em;
}
.newsletter-explore {
  white-space: nowrap;
}
/* the spacing after a word's last letter is kept where the verb comes first
   (it reads as the wider gap in "e x p l o r e  essential mind") and taken
   back where it ends the line, so the link stays truly centred */
.newsletter-explore .explore-de .explore-verb {
  margin-right: -0.25em;
}
html[lang="de"] .newsletter-explore .explore-en,
html:not([lang="de"]) .newsletter-explore .explore-de {
  display: none;
}


/* Slogans: flower only. Client, 2026-11-07: "I want them to appear on the
   flower image but not the video." The pair stays on the flower still of a
   return visit (body.hero-sealed, rules above) and is taken out entirely
   while the film is showing — no fade-in on the scroll, and no resting copy
   over the film for Reduce Motion phones either. */
body:not(.hero-sealed) .hero-slogans {
  display: none;
}
