/* ------------------------------------------------------------------ */
/* Booking and sign-in                                                  */
/* ------------------------------------------------------------------ */
/*
 * A second stylesheet rather than more of app.css, loaded only by the two
 * pages that need it. app.css is on every public timetable in the product -
 * every student, every phone, every printed week - and growing it by a third
 * to style a form four people at each school will ever open is the wrong
 * trade. Everything here uses app.css's own custom properties, so the two stay
 * one design and the dark scheme comes for free.
 *
 * The LAYOUT is the legacy JSF dialog's, on purpose: cascade column, entity
 * panels beside it, then when, then what. That arrangement has been in daily
 * use at ~80 institutions for years. What changed is underneath it.
 */

.booking-wrap
{
    padding: 18px 20px 40px;
}

.booking-cols
{
    display: grid;
    /* The form needs the width: it carries the cascade AND four entity panels
     * side by side, which is the legacy arrangement and the reason the whole
     * dialog reads at a glance. The bookings list is a list. */
    grid-template-columns: minmax(0, 5fr) minmax(0, 2fr);
    gap: 18px;
    align-items: start;
}

@media (max-width: 1250px)
{
    .booking-cols
    {
        grid-template-columns: 1fr;
    }
}

/* panels ----------------------------------------------------------- */

.panel
{
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-l);
    box-shadow: var(--shadow-2);
    padding: 18px 20px 20px;
}

.panel-narrow
{
    max-width: 380px;
    margin: 40px auto;
}

.panel-title
{
    margin: 0 0 16px;
    font-size: 17px;
    font-weight: 650;
    letter-spacing: -.01em;
}

.panel-subtitle
{
    margin: 22px 0 10px;
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-soft);
}

/* forms ------------------------------------------------------------ */

.form
{
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.field-row
{
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
}

.field-row > .field
{
    flex: 1 1 160px;
    min-width: 0;
}

.field
{
    display: flex;
    flex-direction: column;
    gap: 6px;
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
}

.field-narrow
{
    flex: 0 1 140px;
}

.field-label
{
    font-size: 12px;
    font-weight: 600;
    color: var(--ink-soft);
    letter-spacing: .01em;
}

.req
{
    color: var(--danger);
}

.field-inline
{
    display: flex;
    align-items: center;
    gap: 8px;
}

.field-unit
{
    font-size: 13px;
    color: var(--ink-soft);
}

.input
{
    font: inherit;
    font-size: 14px;
    color: var(--ink);
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-m);
    padding: 8px 10px;
    min-width: 0;
}

.input:focus
{
    outline: 2px solid var(--brand);
    outline-offset: 1px;
}

.input:disabled,
.input[readonly]
{
    color: var(--ink-soft);
    background: color-mix(in srgb, var(--surface-2) 60%, transparent);
}

.input-tiny
{
    width: 68px;
}

/*
 * "Repeat every [2] [months, same weekday]".
 *
 * Wider than the other narrow fields because the unit is no longer the word
 * "week(s)" - it is a select whose longest option is a short sentence, and a
 * recurrence rule truncated to "months, same we..." is a rule nobody can
 * check before they press Book. It shrinks before it clips.
 */
.field-repeat
{
    /* The longest option is now a short sentence - "every 2 months, same
     * weekday" - so this field takes what it needs and shrinks before it
     * clips. A recurrence rule truncated to "every 2 months, same we..." is a
     * rule nobody can check before pressing Book. */
    flex: 1 1 360px;
    min-width: 0;
}

/*
 * A row of controls that has nothing to decide.
 *
 * The weekday ticks say nothing about a run of consecutive days - that
 * pattern covers every day the school teaches - so they go quiet. Quiet and
 * still there: a row that vanishes makes the form jump under the cursor and
 * makes people hunt for it when it comes back.
 */
.field.is-off
{
    opacity: .45;
}

/*
 * An entity panel that has nothing to decide either.
 *
 * Outside weeks 1-52 a booking may name rooms and nothing else: groups,
 * subjects and lecturers are re-formed and re-numbered by the year
 * transition, so a booking made two years out against one of them would
 * arrive attached to whoever inherited the number. The three panels stay in
 * place and go quiet, for the same reason the weekday ticks do - and they
 * come back the moment the dates move inside the year again.
 *
 * Quiet only. The checkboxes are still live, because the form is submitted
 * to an API that enforces the rule itself; making the panel look forbidden
 * and leaving the refusal to the server is honest, while disabling the
 * inputs here would silently drop a selection the user had already made
 * before moving the dates.
 */
.epanel.is-off
{
    opacity: .45;
}

.input-repeat
{
    flex: 1 1 auto;
    min-width: 0;
}

/* Under the whole row rather than beside the control: it explains the
 * relationship between two options, not one of them. */
.hint-repeat
{
    margin: -4px 0 0;
    font-size: 12px;
    color: var(--ink-soft);
}

/*
 * "You asked for something that cannot happen."
 *
 * Louder than a hint and quieter than an error, which is exactly what it is:
 * nothing is wrong yet, and pressing Book would still produce a valid - if
 * disappointing - one-day booking. A red error here would be a lie; leaving
 * it grey like the note above would let it pass unread, which is how the
 * person ends up staring at a single-cell availability grid wondering what
 * broke.
 */
.hint-warn
{
    margin: 0;
    padding: 7px 10px;
    border-radius: var(--radius-s);
    border-left: 3px solid #d9a441;
    background: color-mix(in srgb, #d9a441 12%, transparent);
    font-size: 12px;
    line-height: 1.45;
    color: var(--ink);
}

/* The type select wears the type's own colour, because on the timetable the
 * type IS a colour - choosing it from a plain list is choosing what the block
 * will look like blind. The inline background comes from the server so it is
 * right before any script runs; app.js only keeps it right as you change it. */
.input-type
{
    font-weight: 600;
}

.check
{
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 14px;
}

.check.is-off
{
    color: var(--ink-soft);
}

.mailrow
{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    padding: 8px 10px;
    border: 1px dashed var(--line-strong);
    border-radius: var(--radius-m);
}

.daypick
{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.daypick-item
{
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 6px 10px;
    font-size: 13px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--surface-2);
    cursor: pointer;
}

.daypick-item:has(input:checked)
{
    background: color-mix(in srgb, var(--brand) 12%, var(--surface));
    border-color: color-mix(in srgb, var(--brand) 34%, var(--line));
}

.form-actions
{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-top: 4px;
}

/*
 * Pushes Close to the far right.
 *
 * Close is not one of the actions, it is the opposite of them - shoulder to
 * shoulder with Book it was one mis-click away from throwing a filled-in form
 * away. Doing it with a spacer rather than `margin-left: auto` on the button
 * means the row still wraps sensibly on a narrow screen: the spacer collapses
 * and Close simply follows on the next line instead of being stranded.
 */
.form-actions-spacer
{
    flex: 1 1 auto;
    min-width: 0;
}

.inline-form
{
    display: inline;
}

.btn-warn
{
    border-color: color-mix(in srgb, #b8860b 45%, var(--line));
    color: #8a6100;
}

.btn-danger
{
    color: var(--danger);
    border-color: color-mix(in srgb, var(--danger) 35%, var(--line));
}

.btn-small
{
    padding: 4px 10px;
    font-size: 12px;
}

/* the cascade and the entity panels -------------------------------- */

/* A grid, not a wrapping flex row: the cascade and the four panels belong on
 * ONE line, and a flex row with five items simply drops the last one onto a
 * row of its own where it looks like a different section of the form. Below
 * 900px they stack two-and-two, which is honest on a narrow screen. */
.picker-row
{
    display: grid;
    grid-template-columns: minmax(180px, 1.4fr) repeat(4, minmax(110px, 1fr));
    gap: 10px;
    align-items: stretch;
}

@media (max-width: 900px)
{
    .picker-row
    {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .cascade-col
    {
        grid-column: 1 / -1;
    }
}

.cascade-col
{
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.cascade-col .input
{
    font-size: 13px;
    padding: 6px 8px;
}

.epanel
{
    min-width: 0;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--line);
    border-radius: var(--radius-m);
    background: var(--surface-2);
}

.epanel-head
{
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 5px 6px 5px 10px;
    border-bottom: 1px solid var(--line);
    background: color-mix(in srgb, var(--brand) 7%, var(--surface));
    border-radius: var(--radius-m) var(--radius-m) 0 0;
}

.epanel-title
{
    flex: 1;
    font-size: 12px;
    font-weight: 650;
}

/* The two legacy header buttons: clear, and add. Small and quiet - they are
 * always on screen, so they must not shout. Both are real submits; neither
 * needs a script. */
.epanel-btn
{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--surface);
    color: var(--ink-soft);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    list-style: none;
}

.epanel-btn:hover
{
    color: var(--brand-ink);
    border-color: color-mix(in srgb, var(--brand) 40%, var(--line));
}

.epanel-btn::-webkit-details-marker
{
    display: none;
}

.epanel-picker
{
    position: relative;
}

.epanel-picker .picker-pop
{
    right: 0;
    left: auto;
    min-width: 260px;
}

.epanel-body
{
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    align-content: flex-start;
    padding: 8px;
    min-height: 84px;
    max-height: 130px;
    overflow: auto;
}

.chip-sm
{
    font-size: 11.5px;
    padding: 2px 8px;
}

/* A checkbox row inside a picker pop-over. .picker-item already carries the
 * hover and the indent for sub-groups; this only adds the box. */
.picker-check
{
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
}

.picker-check input
{
    flex: none;
}

/* notices ---------------------------------------------------------- */

.notice
{
    margin: 0 0 16px;
    padding: 10px 14px;
    border-radius: var(--radius-m);
    font-size: 14px;
    border: 1px solid var(--line);
    background: var(--surface-2);
}

.notice-error
{
    color: var(--danger);
    background: color-mix(in srgb, var(--danger) 10%, var(--surface));
    border-color: color-mix(in srgb, var(--danger) 36%, var(--line));
}

.notice-warn
{
    color: #8a6100;
    background: color-mix(in srgb, #d9a441 16%, var(--surface));
    border-color: color-mix(in srgb, #d9a441 40%, var(--line));
}

.notice-ok
{
    color: var(--ok);
    background: color-mix(in srgb, var(--ok) 10%, var(--surface));
    border-color: color-mix(in srgb, var(--ok) 34%, var(--line));
}

.hint
{
    margin: 14px 0 0;
    font-size: 12.5px;
    color: var(--ink-soft);
}

.hint-inline
{
    margin: 0;
}

/* ------------------------------------------------------------------ */
/* the overlap screen                                                  */
/* ------------------------------------------------------------------ */

/*
 * A week per row, a weekday per column, as the legacy dialog drew it.
 *
 * The flat list this replaced was technically complete and practically
 * unreadable: forty lines of "date, time, occupied" that a person had to
 * scan like a bank statement. A recurring booking clashes in a PATTERN -
 * "every Tuesday from November" - and a pattern is obvious in a grid and
 * invisible in a list.
 */
.fbwrap
{
    margin: 14px 0 6px;
    overflow-x: auto;   /* a term is wide; the page must not be */
}

.fbgrid
{
    border-collapse: separate;
    border-spacing: 3px;
    font-size: 12px;
    /*
     * FIXED, with the width computed in the template from the number of
     * columns. Automatic layout sizes each column by its content's
     * max-content width - a course title with no line breaks - so a
     * Monday-and-Wednesday booking stretched two cells across the whole
     * panel and left the date marooned in an acre of pink. Fixed layout
     * makes every column 150 px and lets the titles wrap.
     */
    table-layout: fixed;
}

.fbgrid th
{
    font-size: 11px;
    font-weight: 650;
    color: var(--ink-soft);
    text-align: left;
    padding: 2px 4px;
    white-space: nowrap;
}

.fbgrid th.is-weekend
{
    color: color-mix(in srgb, var(--danger) 60%, var(--ink-soft));
}

.fb-wk
{
    /* Under fixed layout the first row's widths decide the columns, so this
     * is the week label's column width - matched by the template's
     * arithmetic for the table as a whole. */
    width: 58px;
}

.fb-wkno
{
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--ink);
}

.fb-wkdate
{
    display: block;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}

.fb-cell
{
    padding: 5px 7px;
    border-radius: var(--radius-s);
    border: 1px solid var(--line);
    vertical-align: top;
    /* An explicit width, because automatic table layout sizes a column from
     * its content's PREFERRED width - and a course title on one unbreakable
     * line has a preferred width of half a metre. Left to itself the table
     * stretched two columns across the whole panel. */
    width: 150px;
}

/* Free, taken, and NEITHER. The third is the one that matters: a fortnightly
 * booking skips half its weeks, and colouring a date the pattern never asked
 * for is a claim about something we did not check. */
.fb-cell.is-free
{
    background: color-mix(in srgb, var(--ok) 14%, var(--surface));
    border-color: color-mix(in srgb, var(--ok) 40%, var(--line));
}

.fb-cell.is-busy
{
    background: color-mix(in srgb, var(--danger) 14%, var(--surface));
    border-color: color-mix(in srgb, var(--danger) 45%, var(--line));
}

.fb-cell.is-none
{
    background: transparent;
    border-color: transparent;
}

.fb-cell.is-weekend.is-free,
.fb-cell.is-weekend.is-busy
{
    /* Weekends stay tinted here as they are on the timetable - a Saturday
     * booking is the one a person double-checks. */
    box-shadow: inset 3px 0 0 color-mix(in srgb, var(--danger) 35%, transparent);
}

.fb-day
{
    display: block;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--ink);
}

.fb-why
{
    display: block;
    margin-top: 3px;
}

/*
 * WRAPS, over two lines, rather than one line cut off with an ellipsis.
 *
 * Two reasons. The obvious one: "Advanced Financial Accountin..." tells you
 * less than two lines of the real title. The one that actually forced it:
 * an unbreakable nowrap line gives the table column an enormous preferred
 * width, and automatic table layout obeys that over any max-width on the
 * text itself. The ellipsis was making the whole grid stretch.
 */
.fb-clash
{
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 10.5px;
    line-height: 1.3;
    color: var(--ink-soft);
    overflow-wrap: anywhere;
}

.fblegend
{
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 4px;
    font-size: 11.5px;
    color: var(--ink-soft);
}

.fbkey
{
    display: inline-block;
    width: 11px;
    height: 11px;
    border-radius: 3px;
    border: 1px solid var(--line);
}

.fbkey.is-free
{
    background: color-mix(in srgb, var(--ok) 40%, var(--surface));
}

.fbkey.is-busy
{
    background: color-mix(in srgb, var(--danger) 40%, var(--surface));
    margin-left: 10px;
}

.fbcount
{
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-weight: 650;
}

/* where it would fit ------------------------------------------------ */

/*
 * The other half of the answer. A refusal that only says no makes the person
 * guess another hour and press Check again; this offers the hours that
 * actually work, computed from the schedule the API already had in hand.
 */
.suggest
{
    margin: 12px 0 4px;
    padding: 12px 14px;
    border-radius: var(--radius-m);
    background: color-mix(in srgb, var(--brand) 6%, var(--surface));
    border: 1px solid color-mix(in srgb, var(--brand) 25%, var(--line));
}

.suggest-title
{
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 700;
}

.suggest-lead
{
    margin: 8px 0 5px;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--ink-soft);
}

.suggest-row
{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.suggest-btn
{
    font-variant-numeric: tabular-nums;
    cursor: pointer;
}

/* availability ----------------------------------------------------- */

.slotlist
{
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 260px;
    overflow: auto;
}

.slot
{
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
    padding: 6px 10px;
    border-radius: var(--radius-s);
    font-size: 13px;
    border-left: 3px solid transparent;
    background: var(--surface-2);
}

.slot.is-free
{
    border-left-color: var(--ok);
}

.slot.is-busy
{
    border-left-color: var(--danger);
    background: color-mix(in srgb, var(--danger) 8%, var(--surface-2));
}

.slot-date
{
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.slot-time,
.slot-state
{
    color: var(--ink-soft);
}

.slot-why
{
    flex: 1 1 100%;
    color: var(--ink-soft);
    font-size: 12px;
}

.slot-conflict + .slot-conflict::before
{
    content: " · ";
}

/* the person's own bookings ---------------------------------------- */

.booklist
{
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.bookitem
{
    position: relative;           /* the stretched link below is measured off this */
    border: 1px solid var(--line);
    border-left: 4px solid var(--spine, var(--line-strong));
    border-radius: var(--radius-m);
    padding: 10px 12px;
    background: var(--surface-2);
}

/* ------------------------------------------------------------------ */
/* A booking row you can press to edit it                              */
/*                                                                     */
/* THE STRETCHED LINK. An empty <a> laid over the whole row, rather    */
/* than the row wrapped in one. Wrapping would put the delete          */
/* confirmation - a <details> holding a form and two buttons - inside  */
/* an anchor, which is invalid HTML and behaves differently in every   */
/* browser. This way the row is one big target, the markup stays       */
/* legal, and the controls that must stay pressable simply sit above   */
/* it in the stacking order.                                           */
/*                                                                     */
/* It is still an ordinary link, so middle-click opens the booking in  */
/* a new tab and the address bar shows where it goes - both of which   */
/* an onclick handler would have taken away.                           */
/* ------------------------------------------------------------------ */

.bookitem-open
{
    position: absolute;
    inset: 0;
    z-index: 0;
    border-radius: inherit;
    cursor: pointer;              /* the hand, over the whole row */
}

/*
 * WHAT TELLS YOU IT IS PRESSABLE. A row that does something on click and
 * looks exactly like a row that does not is a trap; the cursor alone is not
 * enough, and on a touch screen there is no cursor at all. So the row lightens
 * and gains a shadow under the pointer.
 *
 * IT MUST NOT MOVE. The first version also lifted the row a pixel, the way
 * .btn:hover does - and a row is not a button. It CONTAINS buttons, and Delete
 * is one of them: approaching Delete puts the pointer over the row, the row
 * rises a pixel, and the button rises out from under the cursor. Caught in
 * testing as a click on Delete that did nothing, which is exactly how it would
 * be reported - "sometimes I have to press it twice". A pixel is enough when
 * the pointer is near an edge. Colour and shadow say the same thing and hold
 * still while they say it.
 */
.bookitem.is-openable
{
    transition: background-color .12s ease, box-shadow .12s ease;
}

.bookitem.is-openable:hover
{
    background: var(--surface);
    box-shadow: var(--shadow-2);
}

/* Keyboard reaches the same row - the link is focusable, and the ring is
 * drawn around the row rather than around an invisible empty anchor. */
.bookitem-open:focus-visible
{
    outline: 2px solid var(--brand-ink);
    outline-offset: 2px;
}

/* ONLY THE CONTROLS COME BACK UP.
 *
 * This is the part that is easy to get wrong. Raising every child above the
 * sheet would make the row look clickable and not be: the pointer would be
 * over the description text, which sits above the link, and the click would
 * land on nothing. So the text stays underneath - clicks fall through it to
 * the link, which is the whole point - and only the things that have their
 * own job are lifted out of its way.
 *
 * Today that is the delete confirmation. It is the one control in the row
 * that must never be swallowed by "open this for editing", because the two
 * do opposite things and they are eight pixels apart. */
.bookitem .confirm,
.bookitem .bookitem-foot .btn,
.bookitem a:not(.bookitem-open)
{
    position: relative;
    z-index: 1;
}

.bookitem-head
{
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 8px;
    align-items: baseline;
}

.bookitem-type
{
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 650;
    font-size: 14px;
}

.swatch
{
    display: inline-block;
    width: 11px;
    height: 11px;
    border-radius: 3px;
    border: 1px solid rgb(0 0 0 / .18);
}

.bookitem-when
{
    font-size: 12.5px;
    color: var(--ink-soft);
    font-variant-numeric: tabular-nums;
}

.bookitem-desc
{
    margin-top: 4px;
    font-size: 13.5px;
}

.bookitem-meta
{
    margin-top: 4px;
    font-size: 12.5px;
    color: var(--ink-soft);
}

.bookitem-foot
{
    margin-top: 8px;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.badge-ok
{
    color: var(--ok);
}

.badge-wait
{
    color: var(--ink-soft);
}

/* ------------------------------------------------------------------ */
/* "My bookings": a fixed box, not a list that grows without limit     */
/*                                                                     */
/* A departmental secretary can have a thousand bookings. Drawn in     */
/* full, the panel becomes the page and the booking form - the thing   */
/* somebody actually came here to use - ends up above a mile of        */
/* history. A fixed height makes the panel a panel again.              */
/* ------------------------------------------------------------------ */

.booklist
{
    /*
     * Tall enough for about three rows, so it is obviously a list and
     * obviously scrollable, and short enough that the form beside it stays
     * the main thing on the screen.
     */
    max-height: min(52vh, 460px);
    overflow-y: auto;
    overscroll-behavior: contain;

    /* Room for the scrollbar so it does not sit on top of the delete
     * buttons, which are the one control in here nobody wants to hit by
     * accident. */
    padding-right: 4px;
}

/*
 * The standalone page has no form beside it and no reason to be short - it
 * IS the content, and its paging is ordinary links at the bottom.
 */
.booklist-full
{
    max-height: none;
    overflow: visible;
    padding-right: 0;
}

.booklist-foot
{
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin: 10px 0 0;
}

.booklist-count
{
    font-size: 12px;
    color: var(--ink-soft);
    font-variant-numeric: tabular-nums;
}

.bookings-panel
{
    width: min(720px, 100%);
    margin: 0 auto;
}

/*
 * The search box over "My bookings" - see templates/_booksearch.php.
 *
 * ONE ROW THAT WRAPS, not a grid: the field, the button and Clear are three
 * things of very different widths in thirteen languages ("Rechercher",
 * "Durchsuchen", "Pretraži"), and a grid with fixed tracks would either clip
 * the German or waste half the sidebar on the English.
 */
.booksearch
{
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin: 0 0 12px;
}

.booksearch-in
{
    /*
     * flex: 1 with a 0 basis, so the field takes whatever is left after the
     * buttons rather than pushing them onto a second line. min-width comes
     * from .input; without it a flex item refuses to shrink below its
     * content and the row breaks at the first long placeholder.
     */
    flex: 1 1 0;
    min-width: 8ch;
}

/*
 * In the SIDEBAR the panel is narrow, so the field gets its own line and the
 * two buttons sit under it. Anything cleverer puts a 6-character input next
 * to a button that says "Pretraži moje rezervacije".
 */
.booksearch-side .booksearch-in
{
    flex-basis: 100%;
}

/* The browser's own clear cross inside type=search, kept but toned down: it
 * is a control people know, and it should not be darker than the text it
 * sits beside. */
.booksearch-in::-webkit-search-cancel-button
{
    opacity: 0.5;
}

/*
 * The "nothing matched" sentence sits where the rows would have been, so the
 * eye finds it in the same place it was already looking.
 */
.booksearch-empty
{
    margin: 0 0 10px;
}

/*
 * `hidden` HAS TO WIN OVER `.btn`.
 *
 * The browser's own rule for the hidden attribute is `display: none`, and it
 * lives in the user-agent stylesheet - so ANY author rule that sets display
 * beats it, including `.btn { display: inline-flex }`. The result is an
 * element the markup says is hidden, sitting there in plain sight: Clear
 * before anybody has searched, and "All bookings" over a list that is
 * already complete. Both were visible until this rule existed.
 *
 * Scoped to the two places that hide a button rather than written as a
 * blanket `[hidden] { display: none !important }`, because a global
 * !important is the kind of rule that later makes a genuine
 * `display: contents` somewhere else impossible to debug.
 */
.booksearch .btn[hidden],
.booklist-foot .btn[hidden]
{
    display: none;
}

.pager
{
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    margin-top: 16px;
}

.pager-where
{
    font-size: 13px;
    color: var(--ink-soft);
    font-variant-numeric: tabular-nums;
}

/* A dead arrow at the first or last page. Kept in the layout rather than
 * removed, so the two live arrows do not move when you reach an end. */
.btn.is-disabled
{
    opacity: .4;
    pointer-events: none;
}

/*
 * The confirmation styles USED to live here.
 *
 * They moved to app.css when sign-out grew a confirmation of its own: that
 * button is in the header of the timetable, the room overview and the
 * reports, and none of those load this file. Leaving the rules here would
 * have meant an unstyled question - a bare heading and two links floating
 * over the page - on every screen except this one.
 *
 * See "confirmations" in app.css.
 */


/* ------------------------------------------------------------------ */
/* "all day", between the two times and the type                       */
/*                                                                     */
/* It sits in the same row as the time selects and has to line up with */
/* them: the other fields in that row are a label over a control, so    */
/* this one keeps an empty label and puts the tick where the control    */
/* would be. Without it the box floats half a line above its           */
/* neighbours, which reads as a mistake.                                */
/* ------------------------------------------------------------------ */

.field-allday
{
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
}

/*
 * The label is EMPTY and stays: it reserves exactly the height the labels
 * beside it take, so the control below starts on the same line as the two
 * selects. Removing it and nudging with a margin would be a number that
 * needs re-guessing the moment the label's font changes.
 */
.field-allday .field-label
{
    visibility: hidden;
}

.allday
{
    /* Takes the rest of the field - which is precisely the strip the selects
     * occupy - and centres the tick in it. That makes the middle of the box
     * the middle of the select next to it, at any input height. */
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 7px;
    min-height: 34px;
    white-space: nowrap;
    font-size: 13px;
}

.allday input
{
    width: 16px;
    height: 16px;
    accent-color: var(--brand);
}

/* ------------------------------------------------------------------ */
/* THE WHOLE FORM ON ONE SCREEN, DOWN TO THE BOOK BUTTON               */
/* ------------------------------------------------------------------ */
/*
 * Measured on the rendered page (tools/preview-booking.php) at 1920x950,
 * which is a maximised window on a 1920x1080 display once the browser's own
 * chrome is taken off: the Book button's bottom edge sat at 1021 px. Seventy
 * pixels below the fold, on the one control the entire screen exists to
 * reach - so a registrar making a booking scrolls, every time, to find the
 * button they always knew was there.
 *
 * "ne fali puno" - and it did not: 71 px.
 *
 * NOTHING IS REMOVED. Every field, hint, tick and button is still on the
 * screen and still says what it said. What changes is the air between them
 * and the height of the boxes, which is where the 201 px came from:
 *
 *   form row gap        14 -> 7     10 gaps      -70
 *   cascade select gap   6 -> 3      4 gaps      -12
 *   control height      38 -> 32     5 rows      -30  (and -30 in the
 *                                                      cascade column,
 *                                                      which is what sets
 *                                                      the picker row's
 *                                                      height: 237 -> 192)
 *   label-to-control     6 -> 3      6 rows      -18
 *   the `?` button      38 -> 32                 -12  (two rows whose only
 *                                                      content is a 20 px
 *                                                      tick - see below)
 *   the mail row's padding 8 -> 5                 -6
 *   the weekday ticks   33 -> 30                  -3
 *   panel padding    18/20 -> 12/12              -14
 *   the repeat hint's extra top margin           -10
 *   the actions' top margin                       -4
 *
 * Book now ends at 820 instead of 1021.
 *
 * IT TOOK TWO ROUNDS AND THE SECOND IS THE INTERESTING HALF. The first took
 * the obvious 137 px and left Book at 884, which fits a 950 px viewport and
 * did not fit Mišo's. Working out somebody else's window height from a
 * screenshot is archaeology - the scaling factor is unknowable and every
 * estimate contradicted the last. The honest move was to stop estimating and
 * keep taking real fat, and the fat that was left was not in the fields at
 * all: it was in two help buttons and a row of padding, and he had pointed
 * straight at it - "prazan prostor je i ispod prikaži na javnem urniku".
 *
 * THE CONTROL HEIGHT IS THE ONLY PART BEHIND A MEDIA QUERY. 32 px is
 * comfortable for a mouse and mean for a thumb, and a phone scrolls this form
 * whatever we do - there is no screen it would ever fit on - so there is
 * nothing to buy there and a touch target to lose. The spacing changes apply
 * everywhere: tighter rows help a phone too.
 */
.booking-wrap .panel
{
    padding-top: 12px;
    padding-bottom: 12px;
}

.booking-wrap .panel-title
{
    margin-bottom: 8px;
}

.booking-wrap form.form
{
    row-gap: 7px;
}

/* It already has the form's own 9 px above it; 14 more made it float. */
.booking-wrap form.form .hint-repeat
{
    margin-top: 4px;
}

.booking-wrap form.form .form-actions
{
    margin-top: 0;
}

.booking-wrap .cascade-col
{
    row-gap: 3px;
}

/* Label to control. Three is still a gap; six was a gap and a half. */
.booking-wrap form.form .field
{
    gap: 3px;
}

.booking-wrap form.form .field-help
{
    gap: 6px;
}

/*
 * THE `?` BUTTON IS SIZED TO THE CONTROL BESIDE IT, and that is why it turned
 * up in this list at all.
 *
 * `.qhelp` is a fixed 38 px so the mark lines up with the middle of the input
 * it explains. The inputs are 32 now, so 38 was 6 px of nothing - and on the
 * two rows whose content is a 20 px CHECKBOX rather than an input, the `?`
 * was the tallest thing in the row and set its height on its own. That is the
 * "prazan prostor ispod Prikaži na javnem urniku" - a row 38 px tall holding
 * a 20 px tick, because of a help button beside it.
 */
.booking-wrap form.form .qhelp
{
    height: 32px;
}

/* Same story: 8 px of padding around a 20 px tick, on a row that is only ever
 * two ticks and a sentence. */
.booking-wrap form.form .mailrow
{
    padding-top: 5px;
    padding-bottom: 5px;
}

/* The weekday ticks are their own control and were 33 px for no reason the
 * rest of the form shares. */
.booking-wrap form.form .daypick .check
{
    min-height: 30px;
}

@media (min-width: 880px)
{
    .booking-wrap form.form .input,
    .booking-wrap form.form .cascade-sel
    {
        min-height: 32px;
        padding-top: 3px;
        padding-bottom: 3px;
    }
}
