  .layout{display:flex; gap:12px; padding:12px 16px; height:calc(100vh - 80px); height:calc(100dvh - 80px); align-items:stretch}
  @media(max-width:1400px){.layout{gap:8px; padding:8px}}
  @media(max-width:1000px){.layout{flex-direction:column; height:auto}}
  @media(max-width:480px){.layout{padding:6px; gap:6px}}
  .calendar-container{display:flex; gap:12px; flex:1; min-width:0; min-height:0}
  /* Date picker beside the grid at every width down to the phone breakpoint: stacking it above the
     calendar (as this used to below 1200px) spends 260px of height on a block that only needs 200px
     of width, which is exactly the wrong trade on a tablet or a short laptop/landscape window. */
  @media(max-width:700px){.calendar-container{flex-direction:column}}
  .mini-cal{width:220px; background:var(--card); border:1px solid var(--line); border-radius:10px; padding:14px; flex-shrink:0; overflow-y:auto}
  /* Narrower column below 1200px, with the day cells and their gaps tightened to match - at the
     stock 3px gap / 5px padding the seven columns need ~200px of content box and would overflow. */
  @media(max-width:1200px){
    .mini-cal{width:200px; padding:12px 10px}
    .mini-cal-grid{gap:2px}
    .mini-cal-day{padding:5px 2px}
  }
  @media(max-width:700px){.mini-cal{width:100%}}
  .mini-cal-header{display:flex; justify-content:space-between; align-items:center; gap:4px; margin-bottom:12px}
  .mini-cal-header button{padding:4px 6px; font-size:11px}
  .calendar-nav-btn{border-color:var(--accent); color:var(--accent)}
  /* The date picker closes at every size, not just on a phone: it's a 200-220px column here and about
     40% of the schedule's height there, and either is worth reclaiming when you're not picking dates.
     Closed, it always keeps the strip that reopens it, so it can't disappear with no way back. */
  .mini-cal-header .mini-cal-toggle{display:inline-flex; align-items:center; justify-content:center;
    box-sizing:border-box; width:auto; height:auto; padding:4px 6px; border-radius:8px;
    font-size:11px; line-height:normal; color:var(--muted)}
  /* Two carets, one per shape of collapse - down/up where the picker folds upwards into a strip (phones),
     left/right where a whole column slides out of the way. CSS picks which, since the button is rendered
     once for both. */
  .mini-cal-toggle .toggle-caret-v{display:none}
  /* Closing is red, like every other dismiss in the app; reopening isn't, since nothing is being given up. */
  .mini-cal-toggle .toggle-close{color:#C0392B; font-weight:700}
  .mini-cal:not(.collapsed) .mini-cal-toggle{border-color:#C0392B}
  .mini-cal-toggle:hover .toggle-close{color:#E74C3C}
  .mini-cal.collapsed .mini-cal-grid{display:none}
  /* Today's date up the spine of the closed strip - see renderMiniCal. vertical-rl turned 180deg reads
     bottom-to-top, which is the way a strip on the left of the content reads. */
  .mini-cal-spine{display:none}
  @media(min-width:701px){
    .mini-cal.collapsed{display:flex; flex-direction:column}
    .mini-cal.collapsed .mini-cal-spine{display:flex; align-items:center; justify-content:center; flex:1;
      writing-mode:vertical-rl; transform:rotate(180deg); margin-top:6px; overflow:hidden;
      font-size:12px; font-weight:600; letter-spacing:.03em; color:var(--muted); white-space:nowrap}
  }
  @media(min-width:701px){
    /* Closed on anything with a side column: a strip just wide enough for the control that brings it
       back, with everything else - month name, month arrows - hidden rather than crammed into 36px. */
    .mini-cal.collapsed{width:36px; padding:10px 4px; overflow:hidden}
    .mini-cal.collapsed .mini-cal-header{margin-bottom:0; justify-content:center}
    .mini-cal.collapsed .mini-cal-month{display:none}
    .mini-cal.collapsed .mini-cal-header button:not(.mini-cal-toggle){display:none}
    .mini-cal.collapsed .mini-cal-toggle{width:100%; padding:6px 0; font-size:15px;
      border-color:var(--accent); color:var(--accent)}
  }
  /* The label takes all the slack in the header, so ‹ and › are pinned to its two ends instead of being
     pushed around by the month name: "May 2027" and "September 2027" differ by 14px, which had › landing
     in a different place month to month. Centred inside that fixed box, so the name still reads centred. */
  .mini-cal-month{font-weight:700; font-size:13px; text-align:center; flex:1; min-width:0; white-space:nowrap}
  /* Its own feedback, in place of the browser's: the box spans the whole strip now, so a tap wash across
     it reads as a blue bar rather than as a button being pressed. */
  .mini-cal-month:active{color:var(--accent)}
  /* minmax(0,1fr), not 1fr: a plain 1fr can't shrink below the widest day cell's min-content, so the
     seven columns overflowed the picker's width (sideways, inside its own scroll box) instead of
     dividing it - visible as a stray horizontal scrollbar, and worse the narrower it got. */
  .mini-cal-grid{display:grid; grid-template-columns:repeat(7,minmax(0,1fr)); gap:3px; margin-top:10px}
  .mini-cal-day-header{font-size:10px; font-weight:600; color:var(--muted); text-align:center; padding:3px}
  .mini-cal-day{font-size:11px; font-weight:600; padding:5px; text-align:center; border-radius:5px; cursor:pointer; border:1px solid transparent;
    /* No browser tap flash: on Android Chrome it's a translucent blue wash that reads as a stray line on a
       cell this small, and it outlasts the tap. :active below is the app's own answer, and it's instant. */
    -webkit-tap-highlight-color:transparent}
  .mini-cal-day:hover{background:var(--line)}
  .mini-cal-day:active{background:var(--accent); color:#fff}
  .mini-cal-day.other-month{color:var(--muted); font-size:10px}
  .mini-cal-day.today{background:var(--accent); color:#fff}
  .mini-cal-day.selected{border-color:var(--accent); color:var(--accent)}
  .mini-cal-day.today.selected{color:#fff; border-color:#fff}
  .cal{flex:1; min-width:0; min-height:0; background:var(--card); border:1px solid var(--line); border-radius:10px; overflow:hidden; display:flex; flex-direction:column}
  /* Split view: one column per room (see setupGridContainers), each a title strip above the room's own
     grid. Classes rather than inline styles, so the phone and tablet tiers can resize the column - an
     inline style would outrank them. .split-pane is the element the renderers draw into, and they set its
     inner layout themselves, including which axes scroll. */
  .split-col{flex:1; min-width:0; display:flex; flex-direction:column; background:var(--card)}
  .split-title{padding:8px 12px; font-weight:700; font-size:12px; text-align:center; background:var(--paper);
    border-bottom:1px solid var(--line); flex-shrink:0}
  .split-pane{flex:1; min-height:0; display:flex; flex-direction:column; overflow:hidden}
  /* Two columns: the button group, then the date nav pinned to the right. (The clock used to sit in a
     centred third column here - it now lives in the header, see #headerClock.) */
  .cal-toolbar{padding:10px 14px; border-bottom:1px solid var(--line); display:grid; grid-template-columns:1fr auto; gap:10px; align-items:center}
  .cal-toolbar-left{display:flex; gap:8px; align-items:center; flex-wrap:wrap}
  .cal-toolbar-nav{display:flex; gap:3px; align-items:center; justify-content:flex-end; flex-wrap:wrap}
  .cal-toolbar-nav button{flex-shrink:0}
  /* Day(s) / Week / Month are one control, so they get one width at every size rather than each
     sizing to its own label. Phones don't need it - the toolbar grid there already gives them equal
     columns - and a fixed floor could overflow the narrowest screens, so it starts above that. */
  @media(min-width:701px){
    #daysViewDropdown,#weekBtn,#monthBtn{min-width:106px}
    #daysBtn{width:100%}
  }
  /* (The phone toolbar - one named grid row per group of controls - is in the phone section at the
     bottom of this stylesheet; it needs the default stretch alignment, so there's deliberately no
     justify-items override here.) */
  /* One non-wrapping strip that scrolls sideways at every width: in the header's left column a wrapping
     strip would grow the header a row taller the moment another room is configured. */
  .tabs{display:flex; flex-wrap:nowrap; gap:8px; overflow-x:auto; scrollbar-width:none}
  .tabs::-webkit-scrollbar{display:none}
  .tab{flex-shrink:0; border-radius:999px; padding:6px 12px; border:1px solid var(--line); background:transparent; color:var(--ink); cursor:pointer; font-weight:600; font-size:12px}
  .tab:hover{border-color:var(--accent); color:var(--accent)}
  .tab.on{background:var(--accent); color:#fff; border-color:var(--accent)}
  /* Month view grid */
  /* Pinned to the top so the weekday names stay put once the month scrolls (short screens - see
     renderMonthView); they still travel sideways with their own columns. Above .month-cell, which is a
     later sibling and would otherwise paint over them. */
  .month-day-header{background:var(--paper); height:26px; display:flex; align-items:center; justify-content:center; text-align:center; font-weight:600; font-size:12px; line-height:1; border:1px solid var(--line); border-bottom:none; box-sizing:border-box;
    position:sticky; top:0; z-index:5}
  .month-cell{padding:8px; border:1px solid var(--line); overflow-y:auto; cursor:pointer; display:flex; flex-direction:column; background:var(--card)}
  .month-cell.other-month{background:var(--paper); color:var(--muted); font-size:12px; cursor:default; overflow:hidden}
  .month-daynum{font-weight:600; margin-bottom:4px; font-size:13px}
  .month-chip{color:#fff; padding:3px 5px; border-radius:3px; font-size:10px; margin-bottom:2px; cursor:pointer;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; flex-shrink:0}
  @media(max-width:700px){
    .month-cell{padding:4px 3px}
    .month-daynum{font-size:11px; margin-bottom:2px}
    .month-chip{font-size:9px; padding:2px 3px}
    .month-day-header{height:22px; font-size:10px}
  }
  @media(max-width:420px){
    .month-daynum{font-size:10px}
    .month-day-header{height:19px; font-size:9px}
  }

  /* Week view grid - a single scroll container (both axes) whose headers stay put while the grid
     scrolls under them: the day names pinned to the top on vertical scroll, the hour labels pinned to
     the left on horizontal scroll, and the corner cell pinned to both. That way neither axis loses its
     labels, which is what lets the columns keep a legible minimum width and scroll on a phone instead
     of being crushed to fit. */
  .week-columns{display:grid; grid-template-columns:56px repeat(7,minmax(70px,1fr)); min-width:546px}
  /* Stacking order: corner > day names > hour labels > events > slots. Whatever scrolls under a pinned
     header has to pass *behind* it - a booking scrolled up under the day names would otherwise paint on
     top of them (its grid is the later of the two in the DOM) and read as an event floating in the
     header row; likewise one scrolled left under the hour labels. */
  .week-header-row{position:sticky; top:0; z-index:20; background:var(--paper); border-bottom:1px solid var(--line)}
  .week-corner{padding:12px 8px; border-right:1px solid var(--line); position:sticky; left:0; z-index:21; background:var(--paper)}
  .week-header-cell{padding:12px; text-align:center; font-weight:600; font-size:13px; border-top:none}
  /* The label reads as the line the hour starts on, so it sits at the top of its two half-hour rows
     rather than centred in them - hence the asymmetric padding. */
  .week-hour-label{padding:5px 8px 0; text-align:right; font-size:12px; color:var(--muted); font-weight:600;
    border-bottom:1px solid var(--line); background:var(--paper); border-right:1px solid var(--line);
    position:sticky; left:0; z-index:15}
  .week-slot{background:var(--card); border-right:1px solid var(--line); border-bottom:1px solid var(--line); cursor:pointer}
  .week-event{color:#fff; padding:3px 6px; border-radius:4px; font-size:10px; line-height:1.3; cursor:pointer;
    overflow:hidden; z-index:10; margin:1px 3px; border-bottom:1px solid var(--line)}
  @media(max-width:700px){
    .week-header-cell{padding:8px 2px; font-size:11px}
    .week-corner{padding:8px}
    .week-hour-label{padding:4px 6px 0; font-size:10px}
    .week-event{font-size:9px; padding:2px 4px; margin:1px 2px}
  }

  .note{padding:8px 12px; font-size:11px; color:var(--muted); border-top:1px solid var(--line); flex-shrink:0}
  @media(max-width:1000px){.note{font-size:10px}}
