/* ============================================================
   Tutorise portal styles, builds on css/style.css tokens
   ============================================================ */
body.portal { background: var(--surface-2); min-height: 100vh; display: flex; flex-direction: column; }

/* The hidden attribute must win.
   Its only backing is a user-agent rule, [hidden] { display: none }, which any
   class that sets display beats on specificity. So a button with .btn, a form
   with .chat-composer or a grid with .portal-grid stayed on screen while the
   DOM said hidden, and every check that asked el.hidden agreed it was hidden.

   Found on four pages at once: Remove picture offered with no picture to
   remove, the chat composer sitting there before a conversation was chosen,
   the repeat-until fields showing for a one-off slot, and a Cancel button on a
   form with nothing to cancel. .combo-list[hidden] had already been patched
   individually, which suggests this had been met before and treated as a
   one-off. */
[hidden] { display: none !important; }

/* ---------- Portal header ---------- */
.portal-header {
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--border);
}
.portal-header .header-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; min-height: 64px; padding: 0.6rem clamp(1rem, 3vw, 2rem);
  max-width: 1180px; margin: 0 auto;
}
.portal-nav { display: flex; align-items: center; gap: 1.2rem; }
.portal-nav a { font-size: 0.92rem; font-weight: 500; color: var(--muted); }
.portal-nav a:hover { color: var(--brand); }
.portal-main { flex: 1 1 auto; width: 100%; max-width: 1180px; margin: 0 auto; padding: clamp(1.5rem, 4vw, 3rem) clamp(1rem, 3vw, 2rem); }

/* ---------- Auth card (sign in / sign up) ---------- */
.auth-wrap { display: flex; align-items: center; justify-content: center; padding: clamp(1.5rem, 5vw, 4rem) 1rem; flex: 1; }
.auth-card {
  width: 100%; max-width: 440px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 20px; padding: clamp(1.6rem, 4vw, 2.4rem);
  box-shadow: 0 40px 80px -50px rgba(17,38,17,.5);
}
.auth-card h1 { font-size: 1.7rem; color: var(--text); margin-bottom: 0.4rem; }
.auth-sub { color: var(--muted); font-size: 0.95rem; margin-bottom: 1.6rem; }
.auth-foot { margin-top: 1.4rem; font-size: 0.9rem; color: var(--muted); text-align: center; }
.auth-foot a { color: var(--brand); font-weight: 600; }
.auth-foot a:hover { color: var(--accent); }

/* ---------- Forms ---------- */
.field { margin-bottom: 1.05rem; }
.field label { display: block; font-size: 0.85rem; font-weight: 600; color: var(--text); margin-bottom: 0.4rem; }
.field input, .field select, .field textarea {
  width: 100%; font: inherit; color: var(--text);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; padding: 0.7rem 0.85rem; transition: border-color .2s ease, box-shadow .2s ease;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.field textarea { min-height: 90px; resize: vertical; }
.field-hint { font-size: 0.76rem; color: var(--text-3); margin-top: 0.3rem; }
.check-row { display: flex; align-items: flex-start; gap: 0.6rem; font-size: 0.88rem; color: var(--muted); }
.check-row input { width: auto; margin-top: 0.2rem; }
.check-row a { color: var(--brand); font-weight: 600; }

.form-msg { margin: 0.6rem 0 0; padding: 0.7rem 0.9rem; border-radius: 12px; font-size: 0.88rem; }
.form-msg.info  { background: var(--brand-soft); color: var(--green-mid); }
.form-msg.error { background: #fdecec; color: #a12121; border: 1px solid #f3cccc; }
.form-msg.success { background: var(--brand-soft); color: var(--green-mid); border: 1px solid color-mix(in srgb, var(--brand) 25%, transparent); }

/* ---------- Page heading ---------- */
.page-head { margin-bottom: 1.8rem; }
.page-head h1 { font-size: clamp(1.7rem, 4vw, 2.3rem); color: var(--text); }
.page-head p { color: var(--muted); margin-top: 0.4rem; }

/* ---------- Cards / grid ---------- */
.portal-grid { display: grid; gap: 1.25rem; }
.cols-2 { grid-template-columns: repeat(2, 1fr); }
.cols-3 { grid-template-columns: repeat(3, 1fr); }
.panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 16px; padding: 1.5rem; box-shadow: 0 18px 44px -36px rgba(17,38,17,.5);
}
.panel h2 { font-size: 1.15rem; color: var(--text); margin-bottom: 0.8rem; }
.panel .muted { color: var(--muted); font-size: 0.92rem; }
.stack { display: flex; flex-direction: column; gap: 0.8rem; }
.row-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; }

.pill-tag { display: inline-block; font-size: 0.72rem; font-weight: 600; padding: 0.22rem 0.6rem; border-radius: 999px; background: var(--brand-soft); color: var(--green-mid); }
.pill-status { text-transform: capitalize; }
.pill-pending { background:#fff4e0; color:#9a6a12; }
.pill-confirmed,.pill-completed { background: var(--brand-soft); color: var(--green-mid); }
.pill-cancelled,.pill-duplicate { background:#fdecec; color:#a12121; }

/* ---------- Lists ---------- */
.item-card { display: flex; justify-content: space-between; gap: 1rem; align-items: flex-start; padding: 1rem 1.1rem; border: 1px solid var(--border); border-radius: 14px; background: var(--surface); }
.item-card + .item-card { margin-top: 0.7rem; }
.item-title { font-weight: 700; color: var(--text); }
.item-meta { font-size: 0.84rem; color: var(--text-3); margin-top: 0.2rem; }

/* ---------- Tables (admin) ---------- */
.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: 14px; background: var(--surface); }
table.data { width: 100%; border-collapse: collapse; font-size: 0.86rem; min-width: 760px; }
table.data th, table.data td { padding: 0.7rem 0.8rem; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; }
table.data th { background: var(--surface-2); font-weight: 700; color: var(--text); white-space: nowrap; }
table.data tr:last-child td { border-bottom: 0; }

.btn-sm { padding: 0.45rem 0.8rem; font-size: 0.82rem; }
.btn-danger { background: #fdecec; color: #a12121; border: 1px solid #f3cccc; }
.btn-danger:hover { background: #f7dada; }

.filters { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-bottom: 1rem; }
.filters input, .filters select { font: inherit; padding: 0.5rem 0.7rem; border: 1px solid var(--border); border-radius: 10px; background: var(--surface); }

.empty { text-align: center; color: var(--text-3); padding: 2rem 1rem; }
.legal { max-width: 780px; }
.legal h2 { font-size: 1.2rem; margin: 1.6rem 0 0.5rem; color: var(--text); }
.legal p, .legal li { color: var(--muted); line-height: 1.6; }
.legal ul { padding-left: 1.2rem; list-style: disc; margin: 0.5rem 0; }
.legal .draft-note { background: var(--brand-soft); border-radius: 12px; padding: 0.9rem 1.1rem; color: var(--green-mid); font-size: 0.9rem; margin-top: 1.5rem; }

/* ---------- Clienthax vendor branding ---------- */
.portal-header .header-inner { gap: 1.2rem; }
.cx-brand { display: inline-flex; align-items: center; gap: 0.55rem; text-decoration: none; }
.cx-brand img { display: block; }
.cx-sub {
  font-size: 0.62rem; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
  color: var(--text-3); border-left: 1px solid var(--border); padding-left: 0.55rem;
}
.cx-actions { display: flex; align-items: center; gap: 0.9rem; }
.demo-badge {
  font-size: 0.7rem; font-weight: 700; letter-spacing: .3px;
  color: var(--green-mid); background: var(--brand-soft);
  border: 1px solid color-mix(in srgb, var(--brand) 25%, var(--border));
  border-radius: 999px; padding: 0.25rem 0.6rem;
}
.cx-burger { display: none; }
.cx-mobile-nav { display: none; flex-direction: column; gap: 0.2rem; padding: 0.5rem clamp(1rem,3vw,2rem) 1rem; border-top: 1px solid var(--border); background: var(--surface); }
.cx-mobile-nav a { padding: 0.65rem 0.2rem; color: var(--text); border-bottom: 1px solid var(--border); font-weight: 500; }
/* The current page was only a colour change, which is easy to miss against
   five other links. An underline anchors it. */
.portal-nav a { position: relative; padding-bottom: 0.35rem; }
.portal-nav a.active { color: var(--brand); font-weight: 600; }
.portal-nav a.active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -0.15rem;
  height: 2px; border-radius: 2px; background: var(--brand);
}

.portal-footer {
  border-top: 1px solid var(--border);
  background: var(--surface);
  padding: 1.3rem clamp(1rem,3vw,2rem);
}
.cx-powered { display: flex; align-items: center; justify-content: center; gap: 0.5rem; font-size: 0.82rem; color: var(--text-3); }
.cx-powered a { display: inline-flex; opacity: 0.9; }
.cx-powered a:hover { opacity: 1; }

/* ---------- Calendar ---------- */
.cal-layout { display: grid; grid-template-columns: 280px minmax(0, 1fr); gap: 1.5rem; align-items: start; }
.cal-layout > * { min-width: 0; }
.cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.9rem; }
.cal-head h2 { font-size: 1.2rem; color: var(--text); }
.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; width: 100%; max-width: 100%; box-sizing: border-box; }
.cal-dow { text-align: center; font-size: 0.72rem; font-weight: 700; color: var(--text-3); text-transform: uppercase; padding: 0.3rem 0; }
.cal-cell {
  position: relative; aspect-ratio: 1; min-width: 0; box-sizing: border-box;
  border: 1px solid transparent; border-radius: 14px; overflow: hidden;
  background: var(--cal-cell-bg); padding: 0.5rem 0.35rem; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0.3rem; text-align: center;
  transition: background .15s ease, border-color .15s ease;
}
.cal-cell:hover:not(:disabled):not(.is-other) { border-color: var(--brand); background: var(--brand-soft); }
/* The date sits in its own disc, so today can be marked without recolouring the
   whole cell, which would collide with the availability heat shading below. */
.cal-cell .d-num {
  display: inline-flex; align-items: center; justify-content: center;
  /* flex:0 0 auto is load-bearing: without it the disc is a shrinkable flex
     item, and in a narrow cell it compressed to 32x12 - an oval, not a circle. */
  flex: 0 0 auto;
  width: 2rem; height: 2rem; border-radius: 50%;
  background: var(--cal-num-bg); color: var(--text);
  font-weight: 600; font-size: 0.86rem; line-height: 1;
  transition: background .15s ease, color .15s ease;
}
.cal-cell .d-badge { font-size: 0.66rem; font-weight: 500; color: var(--text-3); line-height: 1; }
.cal-cell.is-other { background: transparent; pointer-events: none; }
.cal-cell.is-other .d-num, .cal-cell.is-other .d-badge { visibility: hidden; }
.cal-cell.is-selected { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 32%, transparent); }
.cal-cell.is-today .d-num { background: var(--accent); color: #fff; }
.cal-cell:disabled { cursor: default; }

/* Availability heat, tweak via these variables */
:root {
  --cal-cell-bg: #f4f5f4;   /* resting cell */
  --cal-num-bg:  #e7e9e7;   /* date disc    */
  --av-none: #ececec;
  --av-low: #f6dada;        /* soft rose */
  --av-medlow: #fbe3c8;     /* soft orange */
  --av-med: #fdf0c4;        /* amber */
  --av-high: #d8efdc;       /* green */
}
.cal-cell.availability-none { background: var(--av-none); cursor: not-allowed; }
.availability-none .d-num,.availability-none .d-badge { color: var(--text-3); }
.availability-low       { background: var(--av-low); }
.availability-medium-low{ background: var(--av-medlow); }
.availability-medium    { background: var(--av-med); }
.availability-high      { background: var(--av-high); }

.slots-head { font-weight: 700; color: var(--text); margin-bottom: 0.8rem; }
.slot-row {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  border: 1px solid var(--border); border-radius: 12px; padding: 0.8rem 1rem; margin-bottom: 0.6rem; background: var(--surface);
}
.slot-row .s-time { font-weight: 700; color: var(--text); }
.slot-row .s-count { font-size: 0.82rem; color: var(--text-2); }
.slot-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 0.4rem; vertical-align: middle; }
.slot-row.availability-none { opacity: 0.6; }

.cal-filters .field { margin-bottom: 0.9rem; }
.cal-filters { width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box; }

/* Time range slider */
.range-wrap { padding-top: 0.2rem; }
.range-readout { font-size: 0.82rem; color: var(--text-2); margin-bottom: 0.5rem; }
.range-readout strong { color: var(--brand); }
.range-sliders { position: relative; }
.range-sliders input[type="range"] {
  width: 100%; margin: 0; -webkit-appearance: none; appearance: none;
  height: 4px; border-radius: 999px; background: var(--border); outline: none;
}
.range-sliders input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--surface); box-shadow: 0 1px 4px rgba(0,0,0,.25); cursor: pointer;
}
.range-sliders input[type="range"]::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%; background: var(--accent); border: 2px solid var(--surface); cursor: pointer;
}
.range-sliders input + input { margin-top: 0.55rem; }
.range-mini { display: flex; justify-content: space-between; font-size: 0.68rem; color: var(--text-3); margin-top: 0.3rem; }

/* Dynamic tutor list */
.tutor-list .check-row { padding: 0.15rem 0; }
.tutor-more { margin-top: 0.4rem; font-size: 0.82rem; color: var(--brand); font-weight: 600; background: none; border: 0; cursor: pointer; padding: 0.2rem 0; }
.tutor-more:hover { color: var(--accent); }
.tutor-empty { font-size: 0.84rem; color: var(--text-3); }

/* Mobile filter accordion toggle (hidden on desktop) */
.filters-toggle { display: none; }

/* Searchable dropdown (combobox) */
.combo { position: relative; }
.combo-input { width: 100%; }
.combo-list {
  position: absolute; z-index: 50; left: 0; right: 0; top: calc(100% + 4px);
  max-height: 220px; overflow-y: auto; background: var(--surface);
  border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 18px 40px -24px rgba(17,38,17,.5);
  padding: 0.25rem;
}
.combo-list[hidden] { display: none; }
.combo-opt { padding: 0.5rem 0.6rem; border-radius: 8px; cursor: pointer; font-size: 0.9rem; }
.combo-opt:hover, .combo-opt.active { background: var(--brand-soft); color: var(--green-mid); }
.combo-empty { padding: 0.5rem 0.6rem; color: var(--text-3); font-size: 0.85rem; }

/* Built-in modal */
.modal-overlay { position: fixed; inset: 0; background: rgba(17,38,17,.4); z-index: 300; display: none; align-items: center; justify-content: center; padding: 1rem; }
.modal-overlay.open { display: flex; }
.modal-card { width: 100%; max-width: 460px; background: var(--surface); border: 1px solid var(--border); border-radius: 20px; padding: 1.6rem; box-shadow: 0 40px 80px -40px rgba(17,38,17,.55); }
.modal-card h2 { font-size: 1.3rem; color: var(--text); margin-bottom: 0.5rem; }
.modal-card p { color: var(--muted); font-size: 0.92rem; margin-bottom: 1rem; }
.modal-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1.1rem; }
.legend { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 0.8rem; font-size: 0.72rem; color: var(--text-3); }
.legend span { display: inline-flex; align-items: center; gap: 0.3rem; }
.legend i { width: 12px; height: 12px; border-radius: 3px; display: inline-block; }

/* The full header (logo + 7 links + avatar + Sign out + Clienthax mark)
   measures 948px for an owner. The burger used to appear only at 760px, so
   between 761 and 948 the header overflowed and the page scrolled sideways.
   These four rules therefore switch at 960px, while the layout rules below
   stay at 760 where they belong. */
@media (max-width: 960px) {
  .portal-nav { display: none; }
  .cx-burger { display: flex; }
  .cx-mobile-nav:not([hidden]) { display: flex; }
  .cx-sub { display: none; }
}

@media (max-width: 760px) {
  .cols-2, .cols-3 { grid-template-columns: 1fr; }
  .cal-layout { grid-template-columns: 1fr; gap: 1rem; }

  /* Calendar fits the viewport cleanly on phones */
  .portal-main { overflow-x: hidden; }
  .panel { padding: 1rem; }
  .cal-grid { gap: 3px; }
  .cal-cell { padding: 0.2rem; border-radius: 8px; }
  .cal-cell .d-num { font-size: 0.72rem; }
  .cal-cell .d-badge { font-size: 0.54rem; line-height: 1.1; }
  .cal-dow { font-size: 0.6rem; padding: 0.15rem 0; }

  /* Filters collapse into an accordion above the calendar */
  .filters-toggle { display: flex; width: 100%; justify-content: space-between; align-items: center; }
  .cal-filters.collapsed .cal-filters-body { display: none; }
  .cal-filters { margin-bottom: 1rem; }
}
@media (max-width: 400px) {
  .cal-grid { gap: 2px; }
  .cal-cell .d-badge { font-size: 0.5rem; }
}

/* ===== Patch: brand marks, app shell, touch-safe controls ===== */
body.portal { display: flex; flex-direction: column; min-height: 100vh; }
.portal-main { flex: 1 0 auto; }
.portal-footer { flex-shrink: 0; padding: 0.9rem 1rem; }
.cx-powered { font-size: 0.72rem; }
.cx-powered img { height: 15px; width: auto; }

.tut-brand { display: inline-flex; align-items: center; gap: 0.5rem; text-decoration: none; }
.tut-mark { color: var(--accent); display: inline-flex; }
.tut-name { font-family: 'DM Serif Display', serif; font-size: 1.45rem; color: var(--brand); line-height: 1; }

/* Clienthax wordmark, black "client", green "hax", small green dot, no divider */
.clienthax-brand { display: inline-flex; align-items: center; gap: 0.4rem; }
.clienthax-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--green-mid); display: inline-block; }
.clienthax-wordmark { font-weight: 800; font-size: 0.98rem; letter-spacing: -0.2px; line-height: 1; }
.clienthax-client { color: #171717; }
.clienthax-hax { color: var(--green-mid); }
.clienthax-system-label { font-size: 0.62rem; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; color: var(--text-3); margin-left: 0.15rem; }

/* The month arrows disable at the ends of the allowed range (Jan 2025 to two
   years out). Without this they look identical to an enabled button and the
   limit reads as a broken click. Not part of the reverted restyle. */
.cal-head button:disabled { opacity: 0.4; cursor: default; }

/* Touch-safe calendar controls */
.cal-head button, .cal-cell, .seg-btn { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
.cal-head button { min-width: 44px; min-height: 44px; }

/* Availability segmented toggle */
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; }
.seg-btn { border: 0; background: var(--surface); padding: 0.6rem 1.1rem; font-weight: 600; cursor: pointer; color: var(--text-2); }
.seg-btn.active.avail { background: var(--av-high); color: var(--green-mid); }
.seg-btn.active.block { background: var(--av-low); color: #a12121; }
.seg-note { font-size: 0.85rem; margin-top: 0.6rem; }

/* Booking status calendar colours */
.bk-pending { background: var(--av-med); }
.bk-confirmed { background: var(--av-high); }
.bk-reschedule_requested { background: var(--av-medlow); }
.bk-cancellation_requested { background: var(--av-low); }
.bk-completed { background: #ededed; }
.bk-cancelled { background: #e2e2e2; }

@media (max-width: 760px) {
  .clienthax-system-label { display: inline; }
  .tut-name { font-size: 1.25rem; }
}

/* Help tooltip */
.help-tip { position: relative; display: inline-grid; place-items: center; width: 16px; height: 16px; border-radius: 50%; background: var(--brand-soft); color: var(--green-mid); font-size: 0.7rem; font-weight: 700; cursor: help; margin-left: 0.25rem; }
.help-bubble { position: absolute; bottom: 130%; left: 50%; transform: translateX(-50%); width: 220px; background: var(--surface); color: var(--text-2); border: 1px solid var(--border); border-radius: 10px; padding: 0.6rem 0.7rem; font-size: 0.78rem; font-weight: 400; box-shadow: 0 18px 40px -24px rgba(17,38,17,.5); opacity: 0; visibility: hidden; transition: opacity .15s; z-index: 60; }
.help-tip:hover .help-bubble, .help-tip:focus .help-bubble { opacity: 1; visibility: visible; }

/* Footer Clienthax wordmark */
.powered-clienthax { display: inline-flex; align-items: center; justify-content: center; gap: 0.55rem; text-decoration: none; color: var(--muted, #777); font-family: Inter, system-ui, sans-serif; line-height: 1; }
.powered-label { font-size: 0.78rem; font-weight: 500; color: var(--muted, #777); }
.clienthax-mini-logo { display: inline-flex; align-items: center; gap: 0; font-weight: 900; font-size: 0.98rem; letter-spacing: -0.055em; }
.clienthax-mini-dot { width: 6px; height: 6px; border-radius: 999px; background: #12d66b; margin-right: 0.32rem; transform: translateY(-0.03rem); }
.clienthax-mini-client { color: #151515; }
.clienthax-mini-hax { color: #12d66b; }
.powered-clienthax:hover .clienthax-mini-client, .powered-clienthax:hover .powered-label { color: #000; }

/* Mobile portal header spacing fix */
@media (max-width: 760px) {
  .portal-signout {
    white-space: nowrap;
  }

  .portal-header .header-inner {
    display: grid;
    /* brand | avatar | sign out | burger | vendor mark */
    grid-template-columns: minmax(0, 1fr) auto auto auto auto;
    align-items: center;
    gap: 0.7rem;
    min-height: 62px;
    padding: 0.5rem 0.7rem;
  }

  /* The avatar is a grid item in its own right here, because .cx-actions is
     display:contents on this breakpoint. Without a column of its own it lands
     in the first free cell and displaces everything after it. */
  .cx-avatar {
    grid-column: 2;
    justify-self: center;
  }

  .tut-brand {
    min-width: 0;
    justify-self: start;
  }

  .tut-name {
    font-size: 1.08rem;
  }

  .tut-mark svg {
    width: 17px;
    height: 17px;
  }

  .portal-nav {
    display: none;
  }

  .cx-actions {
    display: contents;
  }

  .portal-signout {
    grid-column: 3;
    justify-self: center;
    font-size: 0.86rem;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
  }

  .cx-burger {
    grid-column: 4;
    justify-self: center;
    display: flex;
    /* The bars are 16px tall inside a 34px box, and this is a column
       flexbox, so without these they stack at the top and the button reads
       as sitting higher than the text beside it. Centring is the fix; the
       old translateY(12px) was compensating for the same thing by hand. */
    justify-content: center;
    align-items: center;
    width: 34px;
    height: 34px;
    padding: 0;
    flex: 0 0 34px;
    transform: none;
  }

  .clienthax-brand--system {
    grid-column: 5;
    justify-self: end;
    display: grid;
    grid-template-columns: auto auto;
    grid-template-areas:
      "dot word"
      ". system";
    column-gap: 0.22rem;
    row-gap: 0.06rem;
    align-items: center;
  }

  .clienthax-brand--system .clienthax-dot {
    grid-area: dot;
    width: 5px;
    height: 5px;
  }

  .clienthax-brand--system .clienthax-wordmark {
    grid-area: word;
    font-size: 0.82rem;
    letter-spacing: -0.055em;
  }

  .clienthax-brand--system .clienthax-system-label {
    grid-area: system;
    margin-left: 0;
    font-size: 0.47rem;
    line-height: 1.05;
    letter-spacing: 0.06em;
    max-width: none;
    white-space: nowrap;
  }
}

@media (max-width: 380px) {
  .portal-header .header-inner {
    gap: 0.22rem;
    padding-inline: 0.45rem;
  }

  .tut-name {
    font-size: 0.98rem;
  }

  .portal-signout {
    font-size: 0.78rem;
  }

  .cx-burger {
    width: 34px;
    height: 34px;
    flex-basis: 34px;
  }

  .clienthax-brand--system {
    max-width: 82px;
  }

  .clienthax-brand--system .clienthax-wordmark {
    font-size: 0.74rem;
  }

  .clienthax-brand--system .clienthax-system-label {
    font-size: 0.44rem;
    letter-spacing: 0.04em;
    max-width: none;
    white-space: nowrap;
  }
}


/* Danger reset buttons (availability) */
.reset-group { margin-top: 1.2rem; padding-top: 1rem; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 0.4rem; }
.btn-reset { text-align: left; background: transparent; border: 1px solid var(--border); color: #a12121; border-radius: 10px; padding: 0.5rem 0.7rem; font-size: 0.82rem; font-weight: 600; cursor: pointer; }
.btn-reset:hover { background: #fdecec; border-color: #f3cccc; }
.btn-reset--all { border-color: #f3cccc; background: #fdecec; }

/* Chat */
.chat-shell { display: grid; grid-template-columns: 300px 1fr; gap: 1rem; min-height: 60vh; }
.chat-list { padding: 0.8rem; overflow-y: auto; max-height: 72vh; }
.conv-item { display: flex; flex-direction: column; gap: 0.15rem; width: 100%; text-align: left; background: transparent; border: 0; border-radius: 10px; padding: 0.6rem 0.7rem; cursor: pointer; }
.conv-item:hover, .conv-item.active { background: var(--brand-soft); }
.conv-title { font-weight: 700; font-size: 0.92rem; color: var(--text); }
.conv-last { font-size: 0.78rem; color: var(--text-3); }
.chat-pane { display: flex; flex-direction: column; padding: 0; overflow: hidden; }
.chat-pane-head { display: flex; align-items: center; gap: 0.6rem; padding: 0.8rem 1rem; border-bottom: 1px solid var(--border); font-weight: 700; color: var(--text); }
.chat-back { display: none; }
.chat-msgs { flex: 1; overflow-y: auto; padding: 1rem; display: flex; flex-direction: column; gap: 0.8rem; max-height: 60vh; }
.msg { display: flex; gap: 0.5rem; align-items: flex-end; max-width: 80%; }
.msg.mine { margin-left: auto; flex-direction: row-reverse; }
.chat-av { width: 30px; height: 30px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.chat-av--init { display: grid; place-items: center; background: var(--brand); color: #fff; font-size: 0.72rem; font-weight: 700; }
.msg-name { font-size: 0.72rem; font-weight: 700; color: var(--text-2); margin-bottom: 0.15rem; }
.msg.mine .msg-name { text-align: right; }
.msg-bubble { background: var(--surface-2); border: 1px solid var(--border); padding: 0.55rem 0.75rem; border-radius: 14px; font-size: 0.92rem; color: var(--text); }
.msg.mine .msg-bubble { background: var(--brand-soft); }
.msg-time { font-size: 0.66rem; color: var(--text-3); margin-top: 0.15rem; }
.msg.mine .msg-time { text-align: right; }
.chat-typing { padding: 0.3rem 1rem; font-size: 0.76rem; color: var(--text-3); }
.chat-input { display: flex; gap: 0.5rem; padding: 0.7rem; border-top: 1px solid var(--border); }
.chat-input input { flex: 1; font: inherit; border: 1px solid var(--border); border-radius: 999px; padding: 0.6rem 0.9rem; }
@media (max-width: 760px) {
  .chat-shell { grid-template-columns: 1fr; }
  .chat-pane { display: none; }
  .chat-shell.show-pane .chat-list { display: none; }
  .chat-shell.show-pane .chat-pane { display: flex; }
  .chat-back { display: inline-flex; }
}
/* Profile avatar */
.avatar-row { display: flex; align-items: center; gap: 1rem; margin-bottom: 1rem; }
.avatar-lg { width: 64px; height: 64px; border-radius: 50%; object-fit: cover; }
.avatar-lg.init { display: grid; place-items: center; background: var(--brand); color: #fff; font-weight: 700; font-size: 1.2rem; }

/* Chat: grouping, deleted, picker, role badges */
.msg-group { display: flex; gap: 0.5rem; align-items: flex-end; max-width: 80%; }
.msg-group.mine { margin-left: auto; flex-direction: row-reverse; }
.grp-head { display: flex; gap: 0.5rem; align-items: baseline; margin-bottom: 0.2rem; }
.msg-group.mine .grp-head { flex-direction: row-reverse; }
.grp-bubbles { display: flex; flex-direction: column; gap: 0.25rem; }
.msg-group.mine .grp-bubbles { align-items: flex-end; }
.msg-bubble { position: relative; background: var(--surface-2); border: 1px solid var(--border); padding: 0.55rem 0.75rem; border-radius: 14px; font-size: 0.92rem; color: var(--text); width: fit-content; }
.msg-group.mine .msg-bubble { background: var(--brand-soft); }
.msg-del { position: absolute; top: -8px; right: -8px; width: 18px; height: 18px; border-radius: 50%; border: 1px solid var(--border); background: #fff; color: #a12121; font-size: 0.7rem; line-height: 1; cursor: pointer; display: none; }
.msg-bubble:hover .msg-del { display: block; }
.msg-deleted { font-size: 0.8rem; color: var(--text-3); font-style: italic; padding: 0.2rem 0.4rem; }
.role-badge { font-size: 0.62rem; font-weight: 700; padding: 0.1rem 0.4rem; border-radius: 999px; vertical-align: middle; }
.role-owner { background: #f3e8ff; color: #6b21a8; }
.role-admin { background: #fdecec; color: #a12121; }
.role-tutor { background: var(--brand-soft); color: var(--green-mid); }
.role-student { background: #eef0ff; color: #3a40a8; }
.pick-list { max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; gap: 0.3rem; }
.pick-row { display: flex; align-items: center; gap: 0.6rem; width: 100%; text-align: left; background: transparent; border: 1px solid var(--border); border-radius: 12px; padding: 0.5rem 0.6rem; cursor: pointer; }
.pick-row:hover { background: var(--brand-soft); }
.pick-meta { display: flex; flex-direction: column; }
.pick-name { font-weight: 600; font-size: 0.9rem; color: var(--text); }
.pick-email { font-size: 0.74rem; color: var(--text-3); }

/* ===== Chat v2: message classes, animation, scroll button, mobile app layout ===== */
.message-group { display: flex; gap: 0.5rem; align-items: flex-end; max-width: 80%; }
.message-group.mine { margin-left: auto; flex-direction: row-reverse; }
.message-group.mine .grp-head { flex-direction: row-reverse; }
.message-group.mine .grp-bubbles { align-items: flex-end; }
.message-bubble { position: relative; background: var(--surface-2); border: 1px solid var(--border); padding: 0.55rem 0.75rem; border-radius: 14px; font-size: 0.92rem; color: var(--text); width: fit-content; max-width: 100%; word-wrap: break-word; overflow-wrap: anywhere; }
.message-group.mine .message-bubble { background: var(--brand-soft); }
.message-bubble .msg-del { position: absolute; top: -8px; right: -8px; width: 18px; height: 18px; border-radius: 50%; border: 1px solid var(--border); background: #fff; color: #a12121; font-size: 0.7rem; line-height: 1; cursor: pointer; display: none; }
.message-bubble:hover .msg-del { display: block; }
.message-deleted-centred { text-align: center; font-size: 0.78rem; color: var(--text-3); font-style: italic; padding: 0.3rem; margin: 0.1rem auto; }

.msg-new { animation: msgIn .22s ease; }
@keyframes msgIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .msg-new { animation: none; } }

.chat-pane { position: relative; }
.chat-head-av { display: inline-flex; }
.chat-head-meta { display: flex; flex-direction: column; line-height: 1.15; }
.chat-head-sub { font-size: 0.72rem; color: var(--text-3); font-weight: 400; }
.chat-back { display: none; background: none; border: 0; font-size: 1.3rem; cursor: pointer; color: var(--brand); padding: 0.2rem 0.4rem; touch-action: manipulation; }

.chat-scroll-bottom { position: absolute; left: 50%; transform: translateX(-50%); bottom: 84px; z-index: 5; width: 40px; height: 40px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface); color: var(--brand); box-shadow: 0 8px 20px -8px rgba(17,38,17,.5); cursor: pointer; font-size: 1.1rem; touch-action: manipulation; }
.chat-new-count { position: absolute; top: -8px; right: -8px; min-width: 18px; height: 18px; padding: 0 4px; border-radius: 999px; background: var(--accent); color: #fff; font-size: 0.66rem; font-weight: 700; display: grid; place-items: center; }

.chat-composer { display: flex; gap: 0.5rem; align-items: flex-end; padding: 0.7rem; border-top: 1px solid var(--border); background: var(--surface); }
.chat-composer textarea { flex: 1; font: inherit; border: 1px solid var(--border); border-radius: 18px; padding: 0.55rem 0.9rem; resize: none; max-height: 120px; line-height: 1.3; }

/* Mobile: real messaging-app layout */
@media (max-width: 760px) {
  .chat-back { display: inline-flex; }
  .chat-shell { display: block; min-height: 0; }
  .chat-list { max-height: none; }
  .chat-pane { display: none; }
  .chat-shell.show-pane .chat-list { display: none; }
  .chat-shell.show-pane .chat-pane {
    display: flex; flex-direction: column;
    /* Not `inset: 0`. That pins the bottom edge to the LAYOUT viewport, which
       the on-screen keyboard does not shrink, so the composer sat underneath
       the keyboard. Pinned to the top instead, with the height driven by the
       VISUAL viewport, which is the one that shrinks. --chat-vh is set by
       js/chat.js from window.visualViewport; 100dvh is the fallback for
       anything without it. */
    /* --chat-vtop follows visualViewport.offsetTop, which is non-zero on iOS
       when opening the keyboard scrolls the page instead of resizing it. */
    position: fixed; top: var(--chat-vtop, 0px); left: 0; right: 0; bottom: auto;
    height: var(--chat-vh, 100dvh);
    /* Above the bottom bar. Both were 200, and the bar is appended to <body>
       after this pane, so at equal z-index the bar won and painted over the
       composer -- which is why a thread opened on a phone with nowhere to
       type. */
    z-index: 250;
    border-radius: 0; border: 0; background: var(--surface);
  }
  /* And the bar itself goes, exactly as the header and footer already do. A
     thread takes the whole screen and the back arrow is the way out, so the
     bar is both redundant and in the way. */
  body.portal:has(.chat-shell.show-pane) .cx-bottom-nav { display: none; }
  .chat-shell.show-pane .chat-pane-head { position: sticky; top: 0; z-index: 6; background: var(--surface); padding-top: max(0.8rem, env(safe-area-inset-top)); }
  .chat-msgs { flex: 1; max-height: none; }
  .chat-composer { position: sticky; bottom: 0; padding-bottom: max(0.7rem, env(safe-area-inset-bottom)); }
  .chat-scroll-bottom { bottom: 92px; }
  /* Chat gives the conversation the whole screen on a phone, so its own
     heading goes. This was unscoped, so it hid the h1 on every page under
     760px: the calendar, bookings, profile and the rest all lost their title
     and description on mobile, which is most of the traffic. */
  .portal-main:has(.chat-shell) .page-head { display: none; }
  body.portal:has(.chat-shell.show-pane) .portal-header,
  body.portal:has(.chat-shell.show-pane) .portal-footer { display: none; }
}

/* Chat unread + nav badge */
.conv-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.conv-unread { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; background: var(--accent); color: #fff; font-size: 0.68rem; font-weight: 700; display: grid; place-items: center; }
.portal-nav a, .cx-mobile-nav a { position: relative; }
.nav-badge { display: inline-grid; place-items: center; min-width: 16px; height: 16px; padding: 0 4px; margin-left: 4px; border-radius: 999px; background: #d9342b; color: #fff; font-size: 0.62rem; font-weight: 700; vertical-align: middle; }

/* ============================================================
   OAuth (Google) sign-in, auth pages
   The logo is an inline SVG on purpose: the CSP is
   img-src 'self' data: blob: https://*.supabase.co, so a remote
   Google-hosted logo would be blocked.
   ============================================================ */
.oauth-list { display: flex; flex-direction: column; gap: 0.6rem; }
.oauth-btn {
  display: flex; align-items: center; justify-content: center; gap: 0.65rem;
  width: 100%; padding: 0.85rem 1rem;
  background: #fff; color: #3c4043;
  border: 1px solid #dadce0; border-radius: 12px;
  font-family: inherit; font-size: 0.95rem; font-weight: 600;
  cursor: pointer; transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.oauth-btn:hover { background: #f7f8f8; border-color: #c6cacd; }
.oauth-btn:active { background: #eef0f1; }
.oauth-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.oauth-btn[disabled] { opacity: 0.6; cursor: default; }
.oauth-btn svg { flex: 0 0 auto; }

.oauth-divider {
  display: flex; align-items: center; gap: 0.8rem;
  margin: 1.3rem 0;
  color: var(--text-3); font-size: 0.78rem;
  text-transform: uppercase; letter-spacing: 0.08em;
}
.oauth-divider::before, .oauth-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--border);
}

/* ---- Legal pages: richer structure for Terms / Privacy ---- */
.legal h3 { font-size: 1rem; margin: 1.1rem 0 0.4rem; color: var(--text); }
.legal .legal-meta { color: var(--text-3); font-size: 0.85rem; margin-top: 0.3rem; }
.legal .toc { background: var(--surface-2, #f7f8f8); border: 1px solid var(--border); border-radius: 12px; padding: 1rem 1.2rem; margin: 1.4rem 0; }
.legal .toc h2 { margin: 0 0 0.5rem; font-size: 0.95rem; }
.legal .toc ol { padding-left: 1.2rem; margin: 0; columns: 2; column-gap: 2rem; }
.legal .toc li { font-size: 0.85rem; margin-bottom: 0.2rem; break-inside: avoid; }
.legal .toc a { color: var(--brand); }
.legal .callout { border: 1px solid var(--border); border-left: 3px solid var(--brand); border-radius: 8px; padding: 0.85rem 1.05rem; margin: 0.9rem 0; font-size: 0.92rem; }
.legal .callout strong { color: var(--text); }
.legal table { width: 100%; border-collapse: collapse; margin: 0.8rem 0; font-size: 0.9rem; }
.legal th, .legal td { text-align: left; padding: 0.55rem 0.7rem; border-bottom: 1px solid var(--border); color: var(--muted); vertical-align: top; }
.legal th { color: var(--text); font-weight: 600; }
@media (max-width: 640px) { .legal .toc ol { columns: 1; } }

/* ---- Show/hide password toggle (js/password-toggle.js) ---- */
.pw-wrap { position: relative; display: block; }
.pw-wrap input { padding-right: 2.9rem; }
.pw-toggle {
  position: absolute; top: 50%; right: 0.5rem; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; padding: 0;
  background: transparent; border: 0; border-radius: 8px;
  color: var(--text-3); cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
.pw-toggle:hover { color: var(--text); background: var(--brand-soft); }
.pw-toggle:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

/* ---- Header identity: role under the wordmark, avatar beside Sign out ----
   The role is ABSOLUTELY POSITIONED, so it occupies no layout space and the
   wordmark sits exactly where it did before this existed. A flex column was
   the obvious approach and the wrong one: it made the brand taller, and
   .tut-brand centres its children, so "Tutorise" rode upwards.

   Text only, no pill: a filled chip next to a serif wordmark reads as a second
   logo competing with the first. Each role gets its own muted colour, dark
   enough to stay legible at this size without pulling the eye off the brand. */
.tut-brand-text { position: relative; display: inline-block; line-height: 1; }
.tut-role {
  position: absolute;
  top: calc(100% + 3px);
  left: 1px;
  font-family: inherit;
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
}
.tut-role--owner   { color: #6E5A85; }   /* dull violet */
.tut-role--admin   { color: #9A5B57; }   /* dull red    */
.tut-role--tutor   { color: #557255; }   /* dull green  */
.tut-role--parent  { color: #87694A; }   /* dull brown  */
.tut-role--student { color: #5A6B85; }   /* dull blue   */

.cx-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; flex: 0 0 auto;
  border-radius: 50%; overflow: hidden;
  background: var(--brand); color: #fff;
  font-size: 0.72rem; font-weight: 700; letter-spacing: .02em;
  border: 1px solid var(--border);
}
.cx-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

@media (max-width: 640px) {
  .tut-role { font-size: 0.52rem; letter-spacing: 0.1em; }
  .cx-avatar { width: 1.75rem; height: 1.75rem; font-size: 0.65rem; }
}

/* ---- Select with a leading icon (subject filter) ---- */
.select-icon { position: relative; display: block; }
.select-icon > svg {
  position: absolute; left: 0.7rem; top: 50%; transform: translateY(-50%);
  color: var(--text-3); pointer-events: none;
}
.select-icon > select { padding-left: 2.2rem; }

/* ---- Mobile bottom navigation ----
   Hidden on desktop, where the header nav already does this job. */
.cx-bottom-nav { display: none; }

@media (max-width: 960px) {
  .cx-bottom-nav {
    display: flex;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 200;
    background: color-mix(in srgb, var(--surface) 94%, transparent);
    backdrop-filter: saturate(180%) blur(12px);
    border-top: 1px solid var(--border);
    /* Clear the iOS home indicator, otherwise the last row of labels sits
       under it and the bar looks cut off. */
    padding: 0.4rem 0.25rem calc(0.4rem + env(safe-area-inset-bottom, 0px));
  }
  .cx-bottom-nav a {
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
    padding: 0.35rem 0.15rem;
    font-size: 0.66rem; font-weight: 500; color: var(--muted);
    text-decoration: none; border-radius: 10px;
    -webkit-tap-highlight-color: transparent;
  }
  .cx-bottom-nav a span {
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .cx-bottom-nav a svg { flex: 0 0 auto; }
  .cx-bottom-nav a.active { color: var(--brand); font-weight: 600; }
  /* The icon carries the active state, so it reads at a glance without the
     label needing to change size and shift the row. */
  .cx-bottom-nav a.active svg {
    background: var(--brand-soft); border-radius: 9px;
    padding: 0.2rem; margin: -0.2rem;
  }
  .cx-bottom-nav a:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

  /* Stop the bar covering the end of the page. */
  body.has-bottom-nav .portal-main { padding-bottom: 5.5rem; }
  body.has-bottom-nav footer { margin-bottom: 4.5rem; }
}


/* ---- Calendar on small screens ----
   A square 7-column grid gives ~35px cells at 320px, which cannot hold a date
   disc and a slot count. Cells become taller than wide instead, matching the
   phone layout in the reference, and the disc scales down with them. */
@media (max-width: 640px) {
  .cal-cell {
    aspect-ratio: auto;
    min-height: 58px;
    padding: 0.4rem 0.15rem;
    gap: 0.2rem;
    border-radius: 11px;
  }
  .cal-cell .d-num { width: 1.6rem; height: 1.6rem; font-size: 0.78rem; }
  .cal-cell .d-badge { font-size: 0.55rem; }
  .cal-grid { gap: 3px; }
}

@media (max-width: 380px) {
  .cal-cell { min-height: 52px; padding: 0.3rem 0.1rem; }
  .cal-cell .d-num { width: 1.45rem; height: 1.45rem; font-size: 0.72rem; }
  .cal-cell .d-badge { font-size: 0.5rem; }
}

/* The Clienthax footer is desktop only: on a phone it sits directly above the
   bottom navigation bar, which reads as two stacked footers. */
@media (max-width: 960px) {
  body.has-bottom-nav .portal-footer { display: none; }
  body.has-bottom-nav footer { margin-bottom: 0; }
}

/* ---- Incoming chat requests (chat sidebar) ----
   A student cannot open a thread with a tutor directly; F-09 requires an
   approved request first, so an adult cannot pull a child into a conversation
   unprompted. This is where staff act on those requests. */
#chat-requests { margin-bottom: 0.8rem; padding-bottom: 0.8rem; border-bottom: 1px solid var(--border); }
.req-head {
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-3); margin-bottom: 0.5rem;
}
.req-row {
  display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
  padding: 0.5rem; border: 1px solid var(--border); border-radius: 12px;
  background: var(--brand-soft); margin-bottom: 0.4rem;
}
.req-who { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.req-name { font-size: 0.85rem; font-weight: 600; color: var(--text); }
.req-actions { display: flex; gap: 0.35rem; flex: 0 0 auto; }
@media (max-width: 640px) {
  .req-row { flex-direction: column; align-items: stretch; }
  .req-actions { justify-content: flex-end; }
}

/* Checkboxes and radios were the only controls still rendering in the
   browser's default blue, against a green and gold palette where the sliders,
   buttons, pills and badges are all styled. One property, and it keeps native
   controls, their keyboard behaviour and their accessibility intact. */
input[type="checkbox"],
input[type="radio"] { accent-color: var(--brand); }

/* Today sits with the next-month arrow so .cal-head stays a three-part row:
   back on the left, the month in the middle, forward controls on the right. */
.cal-head-right { display: inline-flex; align-items: center; gap: 0.5rem; }
.cal-head #cal-today { white-space: nowrap; }
@media (max-width: 420px) {
  .cal-head-right { gap: 0.35rem; }
  .cal-head #cal-today { padding-inline: 0.55rem; font-size: 0.8rem; }
  /* On a 320px screen "August 2026" broke across two lines, which left the
     arrows and Today floating against a two-line title and the whole row
     looking mis-set. It is a three-part row; the middle part has to stay one
     line, so it shrinks instead of wrapping. */
  .cal-head h2 { font-size: 1rem; white-space: nowrap; }
  .cal-head { gap: 0.4rem; }
}
@media (max-width: 340px) {
  /* Title only. The 44px minimum on the arrows is the touch-target floor and
     is not something to trade for a tidier row: at 320px two 44px buttons
     plus Today still leave about 150px, which one line of this fits in. */
  .cal-head h2 { font-size: 0.92rem; }
}

/* ---- Touch targets in the portal header ----
   The audit measured the burger at 34x34 and Sign out at 50x12 on a phone.
   Both are deliberate: at 320px the header row only fits because they are
   small, and that layout is right. But the area that RESPONDS to a finger
   does not have to be the area that is painted.

   So each gets a transparent 44px-tall hit box centred on it. Nothing moves,
   nothing looks different, the taps just land. This matters most for the pair
   of them specifically: a 12px-tall Sign out sits inches from the menu
   button, and missing the menu should not end your session.

   Vertical only, so the boxes cannot collide with each other. */
@media (max-width: 960px) {
  .cx-burger,
  #cx-signout { position: relative; }

  .cx-burger::after,
  #cx-signout::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    /* Vertical only. Widening to 44px made the burger's box and Sign out's
       box overlap at 320px, where the gap between them is smaller than the
       overhang -- which recreates the mis-tap this exists to prevent, just
       less visibly. Height was the real problem anyway: 12px versus 44. */
    width: 100%;
    height: 44px;
    transform: translate(-50%, -50%);
    background: transparent;
  }
}

/* ---- Inline help, the "?" beside a setting ----
   Shown on hover for a mouse, on focus for a keyboard, and on tap for a
   phone. Hover alone would put the explanation out of reach on most of the
   devices this site is actually used on, and this particular setting is one
   people will want explained before they touch it. */
.check-line { display: inline-flex; align-items: center; gap: 0.5rem; cursor: pointer; }
.check-line input { flex: 0 0 auto; }

.hint-dot {
  width: 20px; height: 20px; margin-left: 0.4rem; padding: 0;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface); color: var(--muted);
  font-size: 0.72rem; font-weight: 700; line-height: 1; cursor: pointer;
  vertical-align: middle;
  /* The painted circle stays small; the tap area does not. */
  position: relative;
}
.hint-dot::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.hint-dot:hover, .hint-dot:focus-visible { color: var(--brand); border-color: var(--brand); }

/* Floats over the page. Laid out in flow it pushed Year group and everything
   under it down the moment you opened it, which makes reading the answer feel
   like breaking the form. */
.hint-wrap { position: relative; display: inline-block; }
.hint-bubble {
  position: absolute; z-index: 60;
  top: calc(100% + 0.45rem); left: 0;
  width: max(240px, 22rem); max-width: min(22rem, 80vw);
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface);
  box-shadow: 0 18px 38px -20px rgba(17, 38, 17, 0.35);
  font-size: 0.86rem; line-height: 1.45; font-weight: 400;
  white-space: normal; text-align: left;
}
.hint-bubble span { display: block; margin-bottom: 0.55rem; }
.hint-bubble span:last-child { margin-bottom: 0; }

/* Near the right edge on a narrow screen it would otherwise run off. */
@media (max-width: 560px) {
  .hint-bubble { left: auto; right: 0; width: min(20rem, 78vw); }
}
