CI / No Debug Code (pull_request) Successful in 2s
CI / PHPStan (pull_request) Successful in 2m51s
CI / Coding Standards (pull_request) Successful in 3m6s
CI / Tests (PHP 8.1) (pull_request) Successful in 53s
CI / Tests (PHP 8.2) (pull_request) Successful in 51s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m48s
CI / Build Plugin Zip (pull_request) Skipped
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]>
534 lines
11 KiB
CSS
534 lines
11 KiB
CSS
.us-login-form label {
|
|
display: block;
|
|
margin-bottom: 4px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.us-login-form input[type="text"],
|
|
.us-login-form input[type="password"] {
|
|
width: 100%;
|
|
max-width: 340px;
|
|
padding: 8px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.us-error {
|
|
color: #c00;
|
|
border-left: 4px solid #c00;
|
|
padding-left: 8px;
|
|
}
|
|
|
|
#us-booking-app .us-slot {
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
padding: 12px 16px;
|
|
margin-bottom: 8px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
#us-booking-error {
|
|
color: #c00;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
/*
|
|
* The upcoming-lessons panel. Every rule here is scoped under #us-booking-app —
|
|
* the same id-level specificity .us-slot above uses — because these rows sit in
|
|
* whatever layout the theme provides and carry more content than a calendar
|
|
* cell. Bare class selectors lost to theme rules on div/span/strong, which
|
|
* collapsed the flex layout and piled the details on top of the actions.
|
|
*/
|
|
#us-booking-app .us-my-lessons {
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
#us-booking-app .us-my-lesson {
|
|
box-sizing: border-box;
|
|
max-width: 100%;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
padding: 12px 16px;
|
|
margin-bottom: 8px;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 8px 12px;
|
|
}
|
|
|
|
/*
|
|
* `min-width: 0` lets the title column shrink below its content width — without
|
|
* it a long offering title cannot compress and shoves the status pill and
|
|
* Cancel button out of the row. The flex-basis keeps the details and the
|
|
* actions on one line while there is room, and wraps them once there is not.
|
|
*/
|
|
#us-booking-app .us-my-lesson-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
flex: 1 1 14em;
|
|
min-width: 0;
|
|
}
|
|
|
|
#us-booking-app .us-my-lesson-title,
|
|
#us-booking-app .us-my-lesson-when {
|
|
overflow-wrap: break-word;
|
|
word-break: break-word;
|
|
}
|
|
|
|
#us-booking-app .us-my-lesson-title {
|
|
font-size: 1.05em;
|
|
}
|
|
|
|
#us-booking-app .us-my-lesson-duration {
|
|
font-weight: normal;
|
|
color: #666;
|
|
}
|
|
|
|
#us-booking-app .us-my-lesson-when {
|
|
color: #555;
|
|
}
|
|
|
|
#us-booking-app .us-my-lesson-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px 12px;
|
|
align-items: center;
|
|
}
|
|
|
|
/*
|
|
* Theme-proofing for the leaf text. The row and its two columns are divs with
|
|
* explicit flex rules above, but the text itself still sits in inline elements
|
|
* a theme is free to take out of normal flow — an absolutely positioned,
|
|
* floated or negatively offset span drops the date/time on top of the title and
|
|
* the status pill on top of the Cancel button. Pinning the three properties
|
|
* that would have to change keeps the leaves in flow, at the same id-level
|
|
* specificity the rules above rely on.
|
|
*/
|
|
#us-booking-app .us-my-lesson-title,
|
|
#us-booking-app .us-my-lesson-when,
|
|
#us-booking-app .us-my-lesson-duration,
|
|
#us-booking-app .us-my-lesson-who,
|
|
#us-booking-app .us-lesson-status {
|
|
position: static;
|
|
float: none;
|
|
margin: 0;
|
|
}
|
|
|
|
/*
|
|
* The rows the "Show all" button reveals. `[hidden]` is only a UA-stylesheet
|
|
* rule, so any author rule setting a display on div beats it — the html5-reset
|
|
* `div { display: block }` is still widespread in themes — and the rows the
|
|
* button is meant to gate render anyway. An author !important is the only way
|
|
* to win that cascade.
|
|
*/
|
|
#us-booking-app [hidden] {
|
|
display: none !important;
|
|
}
|
|
|
|
#us-booking-app .us-show-all-lessons {
|
|
background: transparent;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
padding: 6px 14px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
#us-booking-app .us-show-all-lessons:hover {
|
|
border-color: #888;
|
|
}
|
|
|
|
#us-booking-app .us-cancel-lesson {
|
|
background: transparent;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
padding: 4px 12px;
|
|
cursor: pointer;
|
|
color: #c00;
|
|
}
|
|
|
|
#us-booking-app .us-cancel-lesson:hover {
|
|
border-color: #c00;
|
|
}
|
|
|
|
#us-booking-app .us-lesson-status {
|
|
display: inline-block;
|
|
font-size: 0.85em;
|
|
font-weight: 600;
|
|
padding: 2px 10px;
|
|
border-radius: 10px;
|
|
background: #eee;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
#us-booking-app .us-lesson-status-confirmed {
|
|
background: #e2f5e5;
|
|
color: #1a7d2e;
|
|
}
|
|
|
|
#us-booking-app .us-lesson-status-pending {
|
|
background: #fdf3d7;
|
|
color: #8a6d1a;
|
|
}
|
|
|
|
.us-calendar-controls {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.us-filter-toggle {
|
|
padding: 6px 16px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.us-filter-toggle.us-active {
|
|
background: #333;
|
|
border-color: #333;
|
|
color: #fff;
|
|
}
|
|
|
|
.us-type-filter {
|
|
margin-bottom: 12px;
|
|
padding: 8px 12px;
|
|
border: 1px solid #eee;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.us-type-filter-heading {
|
|
display: block;
|
|
margin-bottom: 6px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.us-type-filter-choices {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 8px 16px;
|
|
}
|
|
|
|
.us-type-filter-choice {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
|
|
.us-type-filter-clear {
|
|
margin-left: auto;
|
|
padding: 4px 12px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.us-view-toggle {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
|
|
.us-view-toggle button {
|
|
padding: 6px 16px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.us-view-toggle button.us-active {
|
|
background: #333;
|
|
border-color: #333;
|
|
color: #fff;
|
|
}
|
|
|
|
.us-week-nav {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.us-week-nav button {
|
|
padding: 6px 12px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.us-week-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(7, 1fr);
|
|
gap: 8px;
|
|
}
|
|
|
|
.us-week-day {
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
padding: 8px;
|
|
min-height: 90px;
|
|
}
|
|
|
|
.us-week-day-heading {
|
|
margin: 0 0 8px;
|
|
font-size: 0.85em;
|
|
text-align: center;
|
|
}
|
|
|
|
.us-week-slot {
|
|
display: block;
|
|
width: 100%;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.us-week-empty {
|
|
display: block;
|
|
text-align: center;
|
|
opacity: 0.4;
|
|
}
|
|
|
|
/* The price and pay agreement on a booking / enrolment form. */
|
|
.us-price {
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
padding: 12px 16px;
|
|
margin: 16px 0;
|
|
}
|
|
|
|
.us-price h4 {
|
|
margin: 0 0 8px;
|
|
}
|
|
|
|
.us-price p {
|
|
margin: 0 0 4px;
|
|
}
|
|
|
|
.us-price-amount strong {
|
|
font-size: 1.15em;
|
|
}
|
|
|
|
.us-price-cadence {
|
|
margin-left: 4px;
|
|
}
|
|
|
|
.us-price-tax,
|
|
.us-price-note {
|
|
font-size: 0.9em;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.us-price-agree {
|
|
display: block;
|
|
margin-top: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* The cadence-carrying price on a group-class card. */
|
|
.us-class-price {
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Policy acceptance — booking, enrolment, and signup all render this markup. */
|
|
.us-policy {
|
|
margin: 16px 0;
|
|
}
|
|
|
|
.us-policy h4 {
|
|
margin: 0 0 6px;
|
|
}
|
|
|
|
/*
|
|
* The body is admin-authored HTML sitting inside whatever layout the theme
|
|
* provides, so it gets an explicit reading box rather than inheriting one.
|
|
* `overflow-wrap` breaks pasted URLs instead of letting one long token force
|
|
* the horizontal scrollbar, and the bounded height keeps a long policy from
|
|
* pushing the accept checkbox off the screen.
|
|
*/
|
|
.us-policy-body {
|
|
box-sizing: border-box;
|
|
max-width: 100%;
|
|
max-height: 260px;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
padding: 12px 14px;
|
|
margin-bottom: 8px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
background: #fafafa;
|
|
white-space: normal;
|
|
overflow-wrap: break-word;
|
|
word-break: break-word;
|
|
line-height: 1.5;
|
|
text-align: left;
|
|
}
|
|
|
|
.us-policy-body p,
|
|
.us-policy-body ul,
|
|
.us-policy-body ol {
|
|
margin: 0 0 0.75em;
|
|
max-width: 100%;
|
|
}
|
|
|
|
.us-policy-body ul,
|
|
.us-policy-body ol {
|
|
padding-left: 1.5em;
|
|
}
|
|
|
|
.us-policy-body > :last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.us-policy-accept,
|
|
.us-policies input[type="checkbox"] {
|
|
margin-right: 6px;
|
|
}
|
|
|
|
@media (max-width: 640px) {
|
|
.us-week-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.us-week-day {
|
|
min-height: 0;
|
|
}
|
|
|
|
/*
|
|
* A lesson row carries a title, a date/time, a status pill and a button —
|
|
* more than fits one narrow line, so stack the details above the actions
|
|
* rather than letting them wrap into each other.
|
|
*/
|
|
#us-booking-app .us-my-lesson {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
#us-booking-app .us-my-lesson-info {
|
|
flex: 0 0 auto;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* "Who is this for?" picker — booking and enrolment. Present only on an account
|
|
* that books for more than one person, so it is styled as a normal field rather
|
|
* than a callout.
|
|
*/
|
|
.us-student-picker select {
|
|
max-width: 100%;
|
|
}
|
|
|
|
/*
|
|
* Whose lesson a row in the upcoming panel is — only shown on an account that
|
|
* books for more than one person. Scoped under #us-booking-app like the rest of
|
|
* the panel; as a bare class it was the one rule in the group a theme could
|
|
* outrank on a plain span.
|
|
*/
|
|
#us-booking-app .us-my-lesson-who {
|
|
font-weight: normal;
|
|
opacity: 0.75;
|
|
}
|
|
|
|
/* Parent/guardian signup: the child blocks revealed by the checkbox. */
|
|
.us-guardian {
|
|
margin: 16px 0;
|
|
padding: 12px 14px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.us-guardian legend {
|
|
padding: 0 6px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.us-children-intro {
|
|
margin-top: 0;
|
|
font-size: 0.9em;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
/*
|
|
* Each child is a bordered group so a family of three does not read as one long
|
|
* undifferentiated column of fields.
|
|
*/
|
|
.us-child {
|
|
margin-bottom: 12px;
|
|
padding: 10px 12px;
|
|
border-left: 3px solid #ddd;
|
|
background: #fafafa;
|
|
}
|
|
|
|
.us-child > p:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
/* The guardian's manage-children screen ([us_family]). */
|
|
.us-family-list {
|
|
margin: 0 0 20px;
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
|
|
.us-family-child {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px 12px;
|
|
align-items: baseline;
|
|
padding: 10px 0;
|
|
border-bottom: 1px solid #eee;
|
|
}
|
|
|
|
.us-family-child-name {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.us-family-child-dob {
|
|
font-size: 0.9em;
|
|
opacity: 0.75;
|
|
}
|
|
|
|
/*
|
|
* The actions sit at the far end of the row. Remove is its own form (it posts),
|
|
* so it is forced inline rather than taking a block of its own.
|
|
*/
|
|
.us-family-child-actions {
|
|
display: flex;
|
|
gap: 10px;
|
|
align-items: baseline;
|
|
margin-left: auto;
|
|
}
|
|
|
|
.us-family-remove {
|
|
display: inline;
|
|
}
|
|
|
|
/* The editing row replaces the child's line, so it spans the whole width. */
|
|
.us-family-edit {
|
|
width: 100%;
|
|
}
|
|
|
|
@media (max-width: 640px) {
|
|
/* A name, a date and two actions do not fit one narrow line. */
|
|
.us-family-child-actions {
|
|
margin-left: 0;
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
/* Shown only in block-editor previews (see BlockPreview). */
|
|
.us-editor-note {
|
|
font-size: 0.85em;
|
|
font-style: italic;
|
|
opacity: 0.7;
|
|
}
|