/* ===========================================================================
   RULES — THE INVARIANTS.

   Loaded AFTER style.css and after every feature stylesheet, so what is
   written here WINS. That is the point: style.css says what things look
   like, and this file says what they may never do, whatever anybody writes
   on a page later.

   Each block below exists because the failure it prevents actually happened
   somewhere in this system: a label escaping its button, two sections
   touching edge to edge, a table pushing the whole page sideways on a phone.
   The comments name the failure rather than restating the CSS, because in a
   year the CSS will be obvious and the reason will not.

   NOTHING HERE CHANGES THE LOOK. Every rule either enforces what was already
   intended, or snaps a hand-typed number onto the scale in tokens.css — a
   drift of at most two pixels.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   HIDDEN MEANS HIDDEN. The browser hides an element marked `hidden`
   only by a weak default, so any class that sets `display` — `.btn` sets
   inline-flex — would show it anyway (Bank al Etihad's "Try again", hidden
   after a successful payment, is one). This rule keeps it hidden. Print rules that bring a hidden slide back name it more precisely and
   still win.
   --------------------------------------------------------------------------- */
[hidden] { display: none !important; }



/* ---------------------------------------------------------------------------
   1. GLOBAL — THE PAGE MAY NEVER SCROLL SIDEWAYS.

   A horizontal scrollbar on a phone is the single most common way a layout
   announces it is broken, and it is almost never the fault of the element
   people go looking at. It is one child, somewhere, wider than its parent:
   an image with intrinsic width, a long unbroken URL, a <pre>, a table.

   The cure is not overflow-x: hidden on the body — that hides the symptom and
   takes position: sticky down with it. The cure is teaching every candidate
   to stop at the edge of its parent.
   --------------------------------------------------------------------------- */
img, svg, video, canvas, iframe, embed, object {
  max-width: 100%;
  height: auto;
}
pre, code, kbd, samp {
  max-width: 100%;
  overflow-wrap: break-word;
}
pre { overflow-x: auto; }

/* FLEX AND GRID CHILDREN DO NOT SHRINK BY DEFAULT — and that is the other
   half of the sideways-scroll story. A flex item's min-width is `auto`,
   meaning "never smaller than my content", so one long word in one cell
   widens the whole row and then the whole page. min-width: 0 restores the
   obvious behaviour: shrink, and wrap. */
.grid > *, .grid-2 > *, .grid-3 > *,
.form-grid > *, .toolbar > *, .cal-filters > *, .kv > * {
  min-width: 0;
}


/* ---------------------------------------------------------------------------
   2. BUTTONS — THE LABEL STAYS INSIDE; THE ROW WRAPS.

   THE FAILURE. A button set to white-space: normal with a minimum height,
   in a narrow table cell, wraps "Record visit" to two lines, then one word
   per line, then one letter per line, and the buttons beside it grow tall
   enough to sit on top of each other. This file loads later than style.css,
   so it must agree with style.css's rule (near "Buttons: keep the label
   inside the button") rather than override it.

   THE RULE:
     one line when it fits  a button is as wide as its label; it wraps only
                           when its label is longer than the room it has
                           (white-space: normal, max-width: 100%). A label
                           that is never allowed to wrap does not stop at
                           max-width: the BOX stops there and the text spills
                           out past both edges ("See our services & book an
                           appointment" on a phone). So the cap holds the box
                           and the label wraps inside it, words whole.
     in a table: nowrap    a table row's buttons never wrap (the case above);
                           the table scrolls sideways inside .table-wrap.
     flex: 0 0 auto        never squeezed thinner than its own label by a
                           neighbour (the min-width: 0 on flex children in
                           part 1 is for TEXT cells; a button opts out here),
                           so it narrows only when its container does; if a
                           row of buttons runs out of room the ROW wraps,
                           because .row-actions and .toolbar are flex-wrap.
     min-height: 0         a button is its label plus its padding, so a table
                           row stays as dense as it was designed. Height on
                           touch screens is handled in part 9, and stays out
                           of tables.
   Padding and type size are style.css's business and are not restated.
   --------------------------------------------------------------------------- */
.btn {
  max-width: 100%;
  white-space: normal;
  overflow-wrap: break-word;
  flex: 0 0 auto;
  text-align: center;
  line-height: var(--leading-tight);
  min-height: 0;
  gap: var(--gap-inline);
}
/* a label that wraps does so in balanced lines, so a second line is not one lonely word */
.btn { text-wrap: balance; }
table.data .btn { white-space: nowrap; }

/* AN ICON INSIDE A BUTTON NEVER SHRINKS. Without this the icon is the flex
   item that gives way when the label gets long, so the label survives and
   the icon turns into a sliver. */
.btn > svg, .btn > img, .btn > .icon { flex: 0 0 auto; }

/* ACTION CELLS. .row-actions is what a list's buttons live in (style.css
   makes it flex-wrap). In a table cell the buttons sit at the END of the
   cell — actions read from the right — and the cell never wraps away from
   its buttons; if space runs out the buttons wrap onto a second line inside
   the cell, in order, rather than the cell squeezing them. */
table.data td.row-actions, table.data td > .row-actions {
  justify-content: flex-end;
  gap: var(--space-2);
}
table.data td.row-actions { white-space: normal; }
table.data td .btn { vertical-align: middle; }

/* A ROW OF BUTTONS WRAPS RATHER THAN OVERFLOWS. Three buttons side by side
   fit a desktop and do not fit a phone; the row must be allowed to become
   two rows by itself, without a page author thinking about it. */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-inline);
  align-items: center;
}
/* .btn-block is a full-width button, so it must not sit in a wrapping row
   pretending to be an inline one. */
.btn-row > .btn-block { flex: 1 1 100%; }

/* A FOLD THAT OPENS TAKES ITS OWN LINE. A <details> whose summary is a button
   ("Report", "Skip", "Later") sits in a row of buttons, and a flex row makes
   it exactly as wide as that summary. Opened, the form inside it inherited
   that width — 66px on a phone — so its text box and its button spilled out
   sideways over the next button. Opened, it becomes a full-width line of the
   row (flex-basis only matters inside a flex row; elsewhere it is a block
   already), and the row inside it wraps instead of squeezing. */
details[open] { flex: 1 1 100%; min-width: 0; }
details[open] > form.d-flex { flex-wrap: wrap; }
details[open] > form.d-flex > input:not([type="hidden"]) { flex: 1 1 160px; min-width: 0; }


/* ---------------------------------------------------------------------------
   3. CONTROLS — ONE HEIGHT, SO A ROW LINES UP WITHOUT NUDGING.

   Sized by its own padding and its own font, a select, a text input and a
   button placed on one line come out three different heights, and every
   toolbar then needs a hand-typed margin to correct it.
   --------------------------------------------------------------------------- */
.field input, .field select, .field textarea,
.toolbar input, .toolbar select, .cal-filters select {
  min-height: var(--control-h);
  font-size: var(--text-md);
  font-family: inherit;
  max-width: 100%;
}
.field textarea, .toolbar textarea { min-height: 90px; }
/* EVERY CONTROL WRITES IN THE SITE'S TYPE. Browsers do not pass the page's
   font into form controls: a box outside a .field (the chat's message box, a
   "Why?" note) came out in the browser's own font — a typewriter face in a
   textarea. */
button, input, select, textarea { font-family: inherit; }

/* A BUTTON BESIDE A FIELD IS THE FIELD'S HEIGHT. "Search" beside "Search your
   reminders", "Move it" beside a time, "Filter" beside a category: a small
   button (30px) sat centred beside a 40px box, on dozens of forms. In a row of
   a form or a toolbar that holds a field, the field and the button take the
   control height. Not inside a table: a list's rows stay as dense as designed. */
:where(form, .toolbar, .cal-filters, .btn-row):has(> :is(input:not([type="hidden"], [type="checkbox"], [type="radio"], [type="range"], [type="file"]), select)):not(table.data *)
  > :is(.btn, input:not([type="hidden"], [type="checkbox"], [type="radio"], [type="range"], [type="file"]), select) {
  min-height: var(--control-h);
}

/* A SELECT WITH A LONG OPTION DOES NOT WIDEN THE PAGE. The browser sizes a
   select to its widest option by default — one client with a long name and
   the toolbar is wider than the screen. */
select { max-width: 100%; text-overflow: ellipsis; }


/* ---------------------------------------------------------------------------
   4. SPACE — WHO OWNS THE GAP.

   THE RULE, and it is the most important one in this file:
   **A CONTAINER OWNS THE SPACE BETWEEN ITS CHILDREN. A CHILD NEVER SETS ITS
   OWN OUTER MARGIN.**

   Why it matters. When both do it, you get two opposite complaints at
   once. Two sections TOUCH, because the child's margin
   collapsed into the parent's padding, or a wrapper div appeared between
   them and killed an adjacent-sibling rule. And two other sections sit FAR
   APART, because the container's gap and the child's margin both applied and
   simply added up. Same cause, opposite symptoms, which is why it never
   looks like one bug.

   So: containers use `gap`, or the .stack rule below. Children own nothing.
   --------------------------------------------------------------------------- */
.stack > * + * { margin-top: var(--gap-content); }
.stack-tight > * + * { margin-top: var(--gap-tight); }
.stack-section > * + * { margin-top: var(--gap-section); }
.stack-major > * + * { margin-top: var(--gap-major); }

/* A heading or paragraph as the first or last thing in a card must not add
   space outside the card's own padding — the commonest source of a section
   that looks bottom-heavy. */
.card > :first-child { margin-top: 0; }
.card > :last-child  { margin-bottom: 0; }

.section-title {
  font-size: var(--text-lg);
  font-weight: var(--weight-heavy);
  line-height: var(--leading-tight);
  margin: 0 0 var(--gap-tight);
  overflow-wrap: break-word;
}

/* CARD TO CARD. style.css already gives a card its own bottom margin and
   removes it inside a grid; this only puts that distance on the scale and
   keeps the two halves agreeing, so a card in a grid can never end up with
   gap AND margin. */
.grid, .grid-2, .grid-3 { gap: var(--gap-section); }
.card { margin-bottom: var(--gap-section); padding: var(--card-pad); }
.card:last-child { margin-bottom: 0; }
.grid > .card, .grid-2 > .card, .grid-3 > .card { margin-bottom: 0; }


/* ---------------------------------------------------------------------------
   5. FORMS.
   --------------------------------------------------------------------------- */
.form-grid { gap: var(--gap-content); }
.field { gap: var(--space-1); }
.field label {
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: var(--leading-tight);
  overflow-wrap: break-word;
}
.hint { font-size: var(--text-xs); line-height: var(--leading-body); }

/* A LABEL AND ITS CHECKBOX STAY TOGETHER. The box never shrinks and the text
   wraps beneath itself rather than under the box. */
.check-line {
  display: flex;
  align-items: flex-start;
  gap: var(--gap-tight);
}
.check-line input[type="checkbox"],
.check-line input[type="radio"] { flex: 0 0 auto; }
.check-line > span { min-width: 0; overflow-wrap: break-word; }
/* A tick-box inside a form field is not a text box. The field rules above
   give every input the control height and the full width, which would stand
   the box a line below its own label. */
.field input[type="checkbox"], .field input[type="radio"] { width: auto; min-height: 0; }
.check-line input[type="checkbox"], .check-line input[type="radio"] { margin-top: .2em; }


/* ---------------------------------------------------------------------------
   6. TABLES — THE TABLE SCROLLS, NOT THE PAGE.

   A table has a minimum width it simply cannot go below: enough for its
   columns. On a phone that minimum is usually wider than the screen, and
   something has to give. The right answer is that the TABLE gets its own
   horizontal scroller and the page stays still.

   .table-wrap does that and most tables are already inside one. This adds
   the safety net for the ones that are not: a bare table in a card will
   scroll within the card rather than drag the whole document sideways.
   --------------------------------------------------------------------------- */
.table-wrap { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }
/* THE ONE THING CSS CANNOT DO IS ADD THE WRAPPER, and a table set to
   display: block to scroll on its own stops filling its container. So the
   rule is that every table.data sits inside a .table-wrap — enforced by
   tests/test_ui_system.php, not by a style that quietly breaks widths. */
table.data { font-size: var(--text-sm); }
table.data th { font-size: var(--text-xs); }
table.data th, table.data td { padding: var(--space-3); }

/* Long text in a cell wraps; a long unbroken token breaks rather than
   stretching the column past the viewport. */
table.data td { overflow-wrap: break-word; }


/* ---------------------------------------------------------------------------
   7. TOOLBARS AND PILLS.
   --------------------------------------------------------------------------- */
.toolbar, .cal-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-tight);
  align-items: center;
  margin-bottom: var(--gap-content);
}
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-xs);
  line-height: var(--leading-tight);
  max-width: 100%;
  overflow-wrap: break-word;
}
.empty-state { padding: var(--space-5); font-size: var(--text-sm); }


/* ---------------------------------------------------------------------------
   8. FOCUS — VISIBLE, EVERYWHERE, NOT NEGOTIABLE.

   :focus-visible rather than :focus, so a mouse click does not leave a ring
   behind but a Tab key does. Somebody navigating by keyboard must always be
   able to see where they are; without this they are typing blind.
   --------------------------------------------------------------------------- */
a:focus-visible, button:focus-visible, .btn:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: var(--focus-offset);
  box-shadow: var(--focus-ring);
}


/* ---------------------------------------------------------------------------
   9. SCREEN SIZES — THE THREE TIERS, AND NOTHING ELSE.

   Every responsive decision in the system happens at one of these three
   widths. A page that reaches for a fourth is a page fighting the grid.
   --------------------------------------------------------------------------- */

/* ---- 860px: tablet, or a narrow desktop window ---- */
@media (max-width: 860px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .site-main { padding-left: var(--space-4); padding-right: var(--space-4); }
}

/* ---- 560px: phone ---- */
@media (max-width: 560px) {
  .card { padding: var(--card-pad-sm); }
  .section-title { font-size: var(--text-md); }

  /* A toolbar keeps WRAPPING as a row — the behaviour style.css designed —
     rather than being forced into a stack with every button full width. Its
     text fields may grow to fill a line; its buttons stay button-sized. */
  .toolbar input[type="text"], .toolbar input[type="search"],
  .toolbar input[type="date"], .cal-filters select { flex: 1 1 12rem; min-width: 0; }

  .site-main { padding-left: var(--space-3); padding-right: var(--space-3); }
}

/* ---- 380px: the smallest phones. Nothing new is designed here. ---- */
@media (max-width: 380px) {
  .card { padding: var(--space-3); }
  .btn { padding-left: var(--space-3); padding-right: var(--space-3); }
}

/* ---- TOUCH — a finger is not a cursor ----
   On a device with no fine pointer, every interactive thing gets at least
   44px of height. Checked with `pointer: coarse` rather than by screen
   width, because a touchscreen laptop is wide AND fingered. */
@media (pointer: coarse) {
  /* Standalone buttons and menu rows get a full finger's height. Buttons in
     a LIST do not: a 44px minimum on every "Edit" in a table doubled the
     height of every row on a phone, which is the wrong trade for a list
     somebody scrolls through. Their padding is what makes them tappable. */
  .btn, .icon-btn, .nav-link, .drop-item, .drawer-link { min-height: var(--touch-min); }
  .btn-sm, table.data .btn, .row-actions .btn { min-height: 0; }
}

/* ---- PRINT ----
   A booking sheet or an invoice gets printed. Navigation and buttons are
   noise on paper; a card must not be split across two pages. */
@media print {
  .site-header, .site-footer, .toolbar, .btn, .btn-row, .drawer, .drawer-overlay { display: none !important; }
  .site-main { max-width: none; padding: 0; }
  .card { break-inside: avoid; box-shadow: none; border-color: #999; }
}

/* ---- MOTION ----
   Somebody who has asked their system for less movement has usually asked
   for a reason. The transform on .btn:hover is exactly the kind of thing
   that triggers vestibular symptoms. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .btn:hover { transform: none; }
}


/* ---------------------------------------------------------------------------
   10. A FORM ON ITS WAY — see Kernel\Web\Styles::submitOnce(). The button looks busy so a
   second tap is not invited; the script is what actually refuses it.
   --------------------------------------------------------------------------- */
form.is-sending button[type="submit"], form.is-sending input[type="submit"] {
  opacity: .6;
  cursor: progress;
}

/* ---------------------------------------------------------------------------
   11. PICTURES IN LISTS.

   A photograph in a table or a card list is a fixed BOX that the picture is
   fitted into — never the picture's own size, which is whatever the upload
   happened to be. object-fit: cover keeps a face or a dish centred and
   uncropped in the ugly direction; the box never grows a row. .avatar
   (40px, round) and .avatar-lg (110px) already exist in style.css for
   people; these are the same idea for everything else.
   --------------------------------------------------------------------------- */
.thumb, .thumb-lg {
  display: block;
  object-fit: cover;
  border-radius: var(--radius-sm);
  background: var(--border, #eee);   /* what shows while a picture loads, or if it never does */
  flex: 0 0 auto;
}
.thumb    { width: 48px; height: 48px; }
.thumb-lg { width: 96px; height: 72px; }
/* Inside a table cell a picture sits on the text's centre line, never on
   the baseline with a gap beneath it. */
table.data td img { vertical-align: middle; }
