Two defects, both the same class of theme interference the panel has already been hardened against twice (see the comments at the top of the panel's CSS and in lessonRowHtml).
Text on top of text. The row and its two columns are divs with explicit flex rules, but the leaf text still sits in inline elements — .us-my-lesson-when and .us-lesson-status are spans, the title is a strong. A theme that takes those out of normal flow (absolute positioning, floats, negative margins) drops the date and time onto the lesson title and the status pill onto the Cancel button.
The collapsed rows weren't collapsed..us-my-lessons-more relies on the hidden attribute, but [hidden] { display: none } lives in the UA stylesheet — so the div { display: block } html5-reset that a great many themes still carry outranks it, and the rows the Show all button is meant to gate render regardless.
The fix
Pin position, float and margin on the row's leaf text elements, at the same #us-booking-app id-level specificity the surrounding rules already rely on.
#us-booking-app [hidden] { display: none !important } — an author !important is the only way to beat a theme's element-level display rule here.
Scope .us-my-lesson-who under #us-booking-app; it was the one rule in the group left as a bare class, which is exactly the vulnerability the file's own header comment warns about.
Verification
composer test (762 tests), composer lint and composer cs all pass.
Because none of this is reachable from the PHP suite, I also built a headless-browser harness that renders the exact markup booking.js emits and measures bounding boxes for overlap, across twelve theme CSS patterns at 1024px and 480px:
before
after
patterns clean
7 / 12
12 / 12
The five failures before the change were div{display:block}, div{display:inline}, span{position:absolute}, strong{position:absolute} and a negative-margin theme. The baseline rendering is visually unchanged.
The harness lives outside the repo — it needs a Node/Playwright dev dependency this plugin doesn't currently have. Happy to commit it as a checked-in visual regression test if you want that; say the word and I'll open a follow-up.
Closes #149.
## What was wrong
Two defects, both the same class of theme interference the panel has already been hardened against twice (see the comments at the top of the panel's CSS and in `lessonRowHtml`).
1. **Text on top of text.** The row and its two columns are divs with explicit flex rules, but the leaf text still sits in inline elements — `.us-my-lesson-when` and `.us-lesson-status` are spans, the title is a strong. A theme that takes those out of normal flow (absolute positioning, floats, negative margins) drops the date and time onto the lesson title and the status pill onto the Cancel button.
2. **The collapsed rows weren't collapsed.** `.us-my-lessons-more` relies on the `hidden` attribute, but `[hidden] { display: none }` lives in the UA stylesheet — so the `div { display: block }` html5-reset that a great many themes still carry outranks it, and the rows the **Show all** button is meant to gate render regardless.
## The fix
- Pin `position`, `float` and `margin` on the row's leaf text elements, at the same `#us-booking-app` id-level specificity the surrounding rules already rely on.
- `#us-booking-app [hidden] { display: none !important }` — an author `!important` is the only way to beat a theme's element-level `display` rule here.
- Scope `.us-my-lesson-who` under `#us-booking-app`; it was the one rule in the group left as a bare class, which is exactly the vulnerability the file's own header comment warns about.
## Verification
`composer test` (762 tests), `composer lint` and `composer cs` all pass.
Because none of this is reachable from the PHP suite, I also built a headless-browser harness that renders the exact markup `booking.js` emits and measures bounding boxes for overlap, across twelve theme CSS patterns at 1024px and 480px:
| | before | after |
|---|---|---|
| patterns clean | 7 / 12 | 12 / 12 |
The five failures before the change were `div{display:block}`, `div{display:inline}`, `span{position:absolute}`, `strong{position:absolute}` and a negative-margin theme. The baseline rendering is visually unchanged.
The harness lives outside the repo — it needs a Node/Playwright dev dependency this plugin doesn't currently have. Happy to commit it as a checked-in visual regression test if you want that; say the word and I'll open a follow-up.
The panel's row and its two columns are divs with explicit flex rules, but
the text itself still sits in inline elements. A theme is free to take those
out of normal flow, and when it does the date and time land on the lesson
title and the status pill lands on the Cancel button. Pin position, float
and margin on the leaf elements at the same id-level specificity the rest of
the panel already uses, so a theme rule cannot lift them out of the column.
The rows behind "Show all" had the same shape of problem from the other
direction: `[hidden]` is only a UA-stylesheet rule, so the `div {
display: block }` reset that many themes still ship outranks it and the
collapsed rows render anyway. An author `!important` is the only way to win
that particular cascade.
Verified with a headless-browser harness rendering the exact markup
booking.js emits against twelve theme CSS patterns at two widths: before,
five patterns overlapped text or revealed the hidden rows; after, all pass.
Closes#149
Co-Authored-By: Claude Opus 5 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #149.
What was wrong
Two defects, both the same class of theme interference the panel has already been hardened against twice (see the comments at the top of the panel's CSS and in
lessonRowHtml).Text on top of text. The row and its two columns are divs with explicit flex rules, but the leaf text still sits in inline elements —
.us-my-lesson-whenand.us-lesson-statusare spans, the title is a strong. A theme that takes those out of normal flow (absolute positioning, floats, negative margins) drops the date and time onto the lesson title and the status pill onto the Cancel button.The collapsed rows weren't collapsed.
.us-my-lessons-morerelies on thehiddenattribute, but[hidden] { display: none }lives in the UA stylesheet — so thediv { display: block }html5-reset that a great many themes still carry outranks it, and the rows the Show all button is meant to gate render regardless.The fix
position,floatandmarginon the row's leaf text elements, at the same#us-booking-appid-level specificity the surrounding rules already rely on.#us-booking-app [hidden] { display: none !important }— an author!importantis the only way to beat a theme's element-leveldisplayrule here..us-my-lesson-whounder#us-booking-app; it was the one rule in the group left as a bare class, which is exactly the vulnerability the file's own header comment warns about.Verification
composer test(762 tests),composer lintandcomposer csall pass.Because none of this is reachable from the PHP suite, I also built a headless-browser harness that renders the exact markup
booking.jsemits and measures bounding boxes for overlap, across twelve theme CSS patterns at 1024px and 480px:The five failures before the change were
div{display:block},div{display:inline},span{position:absolute},strong{position:absolute}and a negative-margin theme. The baseline rendering is visually unchanged.The harness lives outside the repo — it needs a Node/Playwright dev dependency this plugin doesn't currently have. Happy to commit it as a checked-in visual regression test if you want that; say the word and I'll open a follow-up.
The panel's row and its two columns are divs with explicit flex rules, but the text itself still sits in inline elements. A theme is free to take those out of normal flow, and when it does the date and time land on the lesson title and the status pill lands on the Cancel button. Pin position, float and margin on the leaf elements at the same id-level specificity the rest of the panel already uses, so a theme rule cannot lift them out of the column. The rows behind "Show all" had the same shape of problem from the other direction: `[hidden]` is only a UA-stylesheet rule, so the `div { display: block }` reset that many themes still ship outranks it and the collapsed rows render anyway. An author `!important` is the only way to win that particular cascade. Verified with a headless-browser harness rendering the exact markup booking.js emits against twelve theme CSS patterns at two widths: before, five patterns overlapped text or revealed the hidden rows; after, all pass. Closes #149 Co-Authored-By: Claude Opus 5 <[email protected]>