/* ==========================================================================
   Open Squash — Portal Brand Layer  v5  (July 2026)
   --------------------------------------------------------------------------
   Makes admin / coaches / lessons / juniors look like the same product as the
   new opensquash.org, without rewriting four large hand-built HTML files.

   HOW TO USE — two levels, one file.

     LEVEL 1 (safe, drop-in anywhere). Add one line to <head>, after the
     portal's own <style> block:
         <link rel="stylesheet" href="os-portal.css">
       → corrects the palette, typography, form controls and focus states.
         Touches nothing that could carry meaning. Zero-risk on any portal.

     LEVEL 2 (opinionated). Also add the opt-in class to <body>:
         <body class="os-brand">
       → restyles cards, buttons, chips, tables and the header to match the
         marketing site. Turn this on one portal at a time and eyeball it.

   WHY THE SPLIT
     v1 of this file restyled `.chip` globally — which silently flattened the
     juniors hub's Green/Blue/Red team chips, where the colour IS the content.
     Generic-looking class names are not always generic. So anything that could
     be semantic now sits behind `.os-brand`, and the always-on layer is limited
     to things that cannot carry meaning.

   ALIASES
     Each portal grew its own names for the same brand colours (--blue,
     --boast, --electric, --green) with hexes hardcoded. Section 2 points those
     at the canonical tokens, so every existing rule inherits corrected values
     for free — and a future brand change is edited here once, not in four files.

   Colours: Brand Guidelines V1 (Nov 2021) — same source as the website.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@600;800&family=Georama:wght@400;500;600;700&display=swap');

/* ---------- 1 · Canonical tokens ------------------------------------------ */
:root{
  --os-electric-green:#8fdaaf;
  --os-boast-blue:#002d78;
  --os-pro-yellow:#fcda01;
  --os-rally-red:#ed1856;
  --os-beginner-blue:#00aaff;
  --os-floor-fawn:#fce6d2;
  --os-get-green:#16403e;
  --os-drive-darkness:#2f2626;

  --os-green-100:#e8f7ef;
  --os-green-200:#c8ecd8;
  --os-green-700:#2c7a52;
  --os-fawn-100:#fef7ef;
  --os-blue-900:#001b48;
  --os-blue-600:#1f4fa0;
  --os-ink-700:#4a3f3f;
  --os-ink-400:#8c8080;
  --os-line:#e7ddd4;

  --os-font-head:'Kanit',system-ui,sans-serif;
  --os-font-body:'Georama',system-ui,sans-serif;

  --os-r-sm:10px; --os-r:14px; --os-r-lg:20px; --os-r-pill:999px;
  --os-shadow-sm:0 1px 2px rgba(0,45,120,.06),0 2px 8px rgba(0,45,120,.05);
  --os-shadow-md:0 2px 4px rgba(0,45,120,.07),0 8px 24px rgba(0,45,120,.08);
  --os-focus:0 0 0 3px rgba(0,170,255,.45);

  /* ---------- 2 · Legacy aliases — UNAMBIGUOUS NAMES ONLY -----------------
     Verified to mean the same thing in every portal, so they can be aliased
     globally. See section 2b for the one name that cannot. */
  --blue:var(--os-boast-blue);
  --blue2:var(--os-blue-600);
  --boast:var(--os-boast-blue);
  --electric:var(--os-electric-green);
  --green-deep:var(--os-get-green);
  --fawn:var(--os-floor-fawn);
  --yellow:var(--os-pro-yellow);
  --red:var(--os-rally-red);
  --sky:var(--os-beginner-blue);
  --ink:var(--os-drive-darkness);
  --dark:var(--os-drive-darkness);
  --muted:var(--os-ink-400);
  --line:var(--os-line);
}

/* ---------- 2b · The collision: `--green` --------------------------------
   `--green` means two different colours depending on the portal:

       lessons-portal   --green:#8fdaaf   (Electric Green — a light accent)
       juniors-hub      --green:#16403e   (Get Green — a dark team colour)

   Aliasing it globally turned the juniors hub's dark "Green" team chips pale,
   dropping white-on-green text below readable contrast — and on that page the
   colour IS the data. So it is resolved per portal instead, by adding ONE of
   these classes to <html> or <body>:

       <body class="os-green-electric">   → lessons, coaches, admin
       <body class="os-green-deep">       → juniors hub

   Anything without one of these keeps whatever the portal already declared,
   which is the safe default.                                              */
.os-green-electric{--green:var(--os-electric-green)}
.os-green-deep{--green:var(--os-get-green)}

/* ==========================================================================
   LEVEL 1 — always on. Nothing here can destroy meaning.
   ========================================================================== */

body{
  font-family:var(--os-font-body);
  color:var(--os-ink-700);
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

/* Headings: the site's Kanit caps. Colour left to the portal so headings
   sitting on navy or green panels don't turn navy-on-navy. */
h1,h2,h3,h4{
  font-family:var(--os-font-head);
  font-weight:800;
  letter-spacing:-.01em;
  line-height:1.1;
}

/* Form controls — element selectors only. Never .field, which is a wrapper
   in the lessons portal, not an input. */
input:not([type=checkbox]):not([type=radio]),
select,
textarea{
  font-family:var(--os-font-body);
  font-size:15px;
  background:#fff;
  border:1px solid var(--os-line);
  border-radius:var(--os-r-sm);
  padding:11px 13px;
  color:var(--os-drive-darkness);
}
input:focus,select:focus,textarea:focus{
  outline:none;
  border-color:var(--os-beginner-blue);
  box-shadow:var(--os-focus);
}
::placeholder{color:var(--os-ink-400)}
:focus-visible{outline:none;box-shadow:var(--os-focus);border-radius:var(--os-r-sm)}

/* Coaches use these on a phone between sessions. */
@media(max-width:640px){
  button,.btn,.cta,.opt-btn{min-height:44px}
}
@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
}
/* Payslips and admin reports get printed. */
@media print{
  body{background:#fff}
  header,.brandbar,button,.btn{box-shadow:none}
  .card,.panel{box-shadow:none;border:1px solid #ccc}
}

/* ==========================================================================
   LEVEL 2 — opt in with <body class="os-brand">
   ========================================================================== */

.os-brand{background:var(--os-fawn-100)}
.os-brand h1,.os-brand h2,.os-brand h3{text-transform:uppercase;color:var(--os-boast-blue)}
.os-brand h1{font-size:clamp(26px,4vw,40px)}
.os-brand h2{font-size:clamp(20px,2.6vw,27px)}
.os-brand .eyebrow{
  font-family:var(--os-font-body);font-weight:700;font-size:11px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--os-rally-red);
}

.os-brand header,.os-brand .brandbar{
  background:var(--os-boast-blue);color:#fff;
  border-radius:0 0 var(--os-r-lg) var(--os-r-lg);
  box-shadow:var(--os-shadow-sm);
}
.os-brand header h1,.os-brand header h2,.os-brand .brandbar h1{color:#fff}

.os-brand .card,.os-brand .panel{
  background:#fff;border:1px solid var(--os-line);
  border-radius:var(--os-r);box-shadow:var(--os-shadow-sm);
}

/* v5 — SCOPE CHANGE. Up to v4 this layer restyled every <button> on the page
   and carved out exceptions with a long :not() chain. Three separate regressions
   came out of that chain being incomplete: the admin .stat cards went navy-on-navy,
   the coach bottom nav overflowed the viewport, and every .tiny text link
   ("Check in", "Clear this day", "Close") became a solid navy pill — as did the
   .seg segmented controls and the .cnav calendar arrows.

   The chain is gone. This layer now brands only buttons that opt in by carrying
   .btn or .cta — classes the portals already use for real calls to action.
   Everything else keeps the portal's own styling, which is what it was designed
   with. .os-raw on a .btn opts an individual one back out. */
/* Shape and type for every branded button. NOT colour — see below. */
.os-brand .btn:not(.os-raw),.os-brand .cta:not(.os-raw){
  font-family:var(--os-font-body);font-weight:700;font-size:14.5px;
  border-radius:var(--os-r-pill);padding:11px 24px;
  cursor:pointer;display:inline-flex;align-items:center;gap:9px;
  transition:transform .12s ease,box-shadow .12s ease;
}

/* The navy fill is only for a PLAIN primary. Every portal ships variant classes
   whose colour is the meaning — .alt is the secondary outline, .warn is amber,
   .danger is red, .mint is mint. v4 painted all of them navy, which put two
   identical navy buttons side by side in every confirm modal: "Cancel" and
   "Yes, cancel" became the same object. Size modifiers (.sm, .full) still fill. */
.os-brand .btn:not(.os-raw):not(.alt):not(.warn):not(.mint):not(.danger):not(.ghost):not(.secondary),
.os-brand .cta:not(.os-raw){
  background:var(--os-boast-blue);color:#fff;border:2px solid transparent;
}
.os-brand .btn:not(.os-raw):hover,.os-brand .cta:not(.os-raw):hover{
  transform:translateY(-1px);box-shadow:var(--os-shadow-md);
}

/* Safety net: text nested inside a restyled button inherits the button's
   colour. Without this, a child span carrying its own dark colour goes
   invisible the moment the button background turns navy. */
.os-brand .btn:not(.os-raw):not(.alt):not(.warn):not(.mint):not(.danger):not(.ghost):not(.secondary) *,
.os-brand .cta:not(.os-raw) *{color:inherit}

/* Navigation is not a button, whatever element it's built from. The coach
   portal's bottom bar is a 5-column grid of bare <button data-tab>s; pill
   padding blew it past the viewport and pushed Desk and More off-screen on a
   phone — precisely the device coaches use it on. They're excluded by the
   :not([data-tab]) above rather than re-styled here: `all:revert` was the
   first attempt and it was worse, because revert discards the portal's OWN
   rules too, not just this layer's. */
.os-brand .ghost{background:transparent;color:var(--os-boast-blue);border-color:var(--os-boast-blue)}
.os-brand .ghost:hover{background:var(--os-boast-blue);color:#fff}
.os-brand [disabled]{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none}

.os-brand table{
  width:100%;border-collapse:collapse;background:#fff;
  border:1px solid var(--os-line);border-radius:var(--os-r);overflow:hidden;
}
.os-brand th{
  background:var(--os-boast-blue);color:#fff;text-align:left;
  font-family:var(--os-font-head);font-weight:600;text-transform:uppercase;
  font-size:12px;letter-spacing:.05em;padding:11px 13px;
}
.os-brand td{padding:11px 13px;border-top:1px solid var(--os-line);font-size:14px}
.os-brand tbody tr:nth-child(even) td{background:var(--os-fawn-100)}
.os-brand tbody tr:hover td{background:var(--os-green-100)}

/* ==========================================================================
   Opt-in utilities — always available, never automatic.
   Use these for NEW portal UI so it matches the site from the start.
   ========================================================================== */

.os-btn{
  display:inline-flex;align-items:center;gap:9px;
  font-family:var(--os-font-body);font-weight:700;font-size:14.5px;
  border-radius:var(--os-r-pill);padding:11px 24px;
  border:2px solid transparent;background:var(--os-boast-blue);color:#fff;
  cursor:pointer;text-decoration:none;
}
.os-btn--accent{background:var(--os-electric-green);color:var(--os-boast-blue)}
.os-btn--ghost{background:transparent;color:var(--os-boast-blue);border-color:var(--os-boast-blue)}
.os-btn--danger{background:var(--os-rally-red);color:#fff}

.os-chip{
  display:inline-flex;align-items:center;border-radius:var(--os-r-pill);
  padding:4px 13px;font-size:12px;font-weight:700;
  background:var(--os-green-100);color:var(--os-green-700);
  border:1px solid var(--os-green-200);
}
.os-chip--navy{background:var(--os-boast-blue);color:#fff;border-color:var(--os-boast-blue)}
.os-chip--warn{background:var(--os-pro-yellow);color:var(--os-boast-blue);border-color:var(--os-pro-yellow)}
.os-chip--alert{background:#fdeaf0;color:#8f1136;border-color:#f5c6d2}

.os-card{
  background:#fff;border:1px solid var(--os-line);
  border-radius:var(--os-r);box-shadow:var(--os-shadow-sm);padding:20px;
}
.os-card--accent{background:var(--os-green-100);border-color:var(--os-green-200)}
.os-card--invert{background:var(--os-boast-blue);border-color:var(--os-boast-blue);color:rgba(255,255,255,.86)}
.os-card--invert h1,.os-card--invert h2,.os-card--invert h3{color:#fff}

.os-eyebrow{
  font-weight:700;font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--os-rally-red);
}
.os-muted{color:var(--os-ink-400);font-size:13px}

/* ==========================================================================
   Desk POS pilot
   ========================================================================== */
.pilot-dot{margin-left:6px;padding:1px 6px;border-radius:999px;background:var(--amber);color:var(--navy);font-size:9px;text-transform:uppercase}
.pos-shell{max-width:1200px;margin:0 auto;padding:26px 18px 50px}
.pos-hero{display:flex;justify-content:space-between;align-items:flex-start;gap:20px;margin-bottom:18px}
.pos-hero h1{font:800 30px/1 var(--os-font-head);text-transform:uppercase;color:var(--os-boast-blue);margin:5px 0 7px}
.pos-hero p{margin:0;color:var(--os-ink-400);max-width:660px}
.pos-layout{display:grid;grid-template-columns:minmax(0,1fr) 370px;gap:18px;align-items:start}
.pos-main{display:flex;flex-direction:column;gap:16px;min-width:0}
.pos-step{padding:20px}
.pos-stephead{display:flex;gap:12px;align-items:flex-start;margin-bottom:16px}
.pos-stephead>span{display:flex;align-items:center;justify-content:center;flex:none;width:28px;height:28px;border-radius:50%;background:var(--os-boast-blue);color:#fff;font-weight:800}
.pos-stephead h2,.pos-cart h2,.pos-recent h2{font:700 19px/1.15 var(--os-font-head);color:var(--os-boast-blue);margin:1px 0 4px}
.pos-stephead p{margin:0;color:var(--os-ink-400);font-size:13px}
.pos-customer-find{display:flex;gap:10px}
.pos-customer-find .field{margin:0;flex:1}
.pos-results{margin-top:8px;border-radius:10px;overflow:hidden}
.pos-results:empty{display:none}
.pos-person{display:flex;align-items:flex-start;gap:12px;border:1px solid var(--os-green-200);background:var(--os-green-100);border-radius:12px;padding:14px}
.pos-avatar{display:flex;align-items:center;justify-content:center;flex:none;width:42px;height:42px;border-radius:50%;background:var(--os-boast-blue);color:#fff;font:800 19px var(--os-font-head)}
.pos-personbody{flex:1;min-width:0}
.pos-personbody>b,.pos-personbody>span,.pos-personbody>small{display:block}
.pos-personbody>b{color:var(--os-boast-blue);font-size:16px}
.pos-personbody>span,.pos-personbody>small{color:var(--os-ink-400);font-size:12.5px}
.pos-personchips{display:flex;flex-wrap:wrap;gap:5px;margin:8px 0 5px}
.pos-personchips .os-chip{font-size:10.5px;padding:3px 9px}
.pos-catalog-tools .field{margin:0}
.pos-cats{display:flex;gap:7px;overflow-x:auto;padding:10px 0 12px}
.pos-cat{white-space:nowrap;border:1px solid var(--os-line);background:#fff;border-radius:999px;padding:7px 12px;color:var(--os-boast-blue);font-weight:700;cursor:pointer}
.pos-cat.on{background:var(--os-boast-blue);border-color:var(--os-boast-blue);color:#fff}
.pos-products{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.pos-product{display:flex;align-items:center;gap:12px;border:1px solid var(--os-line);border-radius:12px;padding:13px;background:#fff}
.pos-productbody{flex:1;min-width:0}
.pos-productbody>div:first-child{display:flex;justify-content:space-between;gap:8px}
.pos-product h3{font:700 15px/1.2 var(--os-font-head);color:var(--os-boast-blue);margin:3px 0}
.pos-product p{font-size:11px;color:var(--os-ink-400);margin:3px 0}
.pos-productcat{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--os-ink-400)}
.pos-price{color:var(--os-boast-blue);white-space:nowrap}
.pos-product .os-btn{padding:8px 13px;font-size:12.5px}
.pos-product .os-chip{font-size:10px;padding:2px 8px}
.pos-stock{font-size:11px;color:var(--os-ink-400);margin-top:5px}
.pos-payments{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}
.pos-payment{display:flex;gap:9px;border:1px solid var(--os-line);border-radius:12px;padding:13px;cursor:pointer}
.pos-payment.on{border-color:var(--os-electric-green);box-shadow:inset 0 0 0 1px var(--os-electric-green);background:var(--os-green-100)}
.pos-payment.disabled{opacity:.45;cursor:not-allowed}
.pos-payment input{margin-top:3px;accent-color:var(--os-boast-blue)}
.pos-payment b,.pos-payment small{display:block}
.pos-payment b{color:var(--os-boast-blue);font-size:14px}
.pos-payment small{color:var(--os-ink-400);font-size:11.5px;margin-top:2px}
.pos-cart{position:sticky;top:135px;padding:18px}
.pos-carttop{display:flex;justify-content:space-between;gap:10px;align-items:flex-start;border-bottom:1px solid var(--os-line);padding-bottom:13px}
.pos-cartempty{text-align:center;color:var(--os-ink-400);padding:30px 8px}
.pos-cartempty>span{display:block;font-size:28px;margin-bottom:7px}
.pos-cartempty b{display:block;color:var(--os-boast-blue)}
.pos-cartempty p{font-size:12px;margin:4px 0}
.pos-cartlines{padding:4px 0}
.pos-cartline{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:10px;align-items:center;padding:11px 0;border-bottom:1px solid var(--os-line)}
.pos-cartline>div:first-child b,.pos-cartline>div:first-child span{display:block}
.pos-cartline>div:first-child b{color:var(--os-boast-blue);font-size:13px}
.pos-cartline>div:first-child span{color:var(--os-ink-400);font-size:11px}
.pos-qty{display:flex;align-items:center;gap:5px}
.pos-qty button{width:25px;height:25px;border:1px solid var(--os-line);background:#fff;border-radius:50%;color:var(--os-boast-blue);cursor:pointer}
.pos-saleclub{border-top:1px solid var(--os-line);padding-top:13px}
.pos-saleclub label{font-size:11px;font-weight:700;color:var(--os-ink-400)}
.pos-saleclub .field{margin:3px 0 0;padding:8px 9px;font-size:12px}
.pos-adjust{display:grid;grid-template-columns:90px 1fr;gap:8px;border-top:1px solid var(--os-line);padding-top:13px}
.pos-adjust label{font-size:11px;font-weight:700;color:var(--os-ink-400)}
.pos-adjust label:last-child{grid-column:1/-1}
.pos-adjust .field{margin:3px 0 0;padding:8px 9px;font-size:12px}
.pos-totals{padding:13px 0}
.pos-totals>div{display:flex;justify-content:space-between;font-size:13px;padding:3px 0}
.pos-totals .grand{border-top:1px solid var(--os-line);margin-top:7px;padding-top:10px;font-size:17px;color:var(--os-boast-blue)}
.pos-safety{text-align:center;color:var(--os-ink-400);font-size:11px;line-height:1.35;margin:8px 10px 0}
.pos-success{display:flex;flex-direction:column;background:var(--os-green-100);border:1px solid var(--os-green-200);border-radius:10px;padding:10px;margin-top:10px;color:var(--os-green-700)}
.pos-success span{font-size:11px}
.pos-recent{padding:18px}
.pos-receipt{display:flex;justify-content:space-between;gap:12px;padding:10px 0;border-top:1px solid var(--os-line)}
.pos-receipt>div:last-child{text-align:right}
.pos-receipt b,.pos-receipt span{display:block}
.pos-receipt b{font-size:12.5px;color:var(--os-boast-blue)}
.pos-receipt span{font-size:11px;color:var(--os-ink-400)}
@media(max-width:900px){
  .pos-layout{grid-template-columns:1fr}
  .pos-cart{position:static}
}
@media(max-width:620px){
  .pos-shell{padding:18px 12px 40px}
  .pos-hero{flex-direction:column}
  .pos-products,.pos-payments{grid-template-columns:1fr}
  .pos-customer-find{flex-direction:column}
  .pos-adjust{grid-template-columns:1fr}
  .pos-adjust label:last-child{grid-column:auto}
}

/* The recurring list's booked marks and its week-check bar. Deliberately quiet: the list is a
   reference document first, and a wall of red on a night when PlayByPoint is unreachable would
   read as "nothing is booked" rather than "nobody asked yet". */
.bkmark{display:inline-block;margin-left:8px;padding:1px 8px;border-radius:999px;font-size:11px;
        font-weight:800;letter-spacing:.02em;vertical-align:middle}
.bkmark.yes{background:#e6f4ea;color:#1c6b39}
.bkmark.no{background:#fdf0e2;color:#9a5b16}
.bkmark.off{background:#eef1f7;color:#7c7e86}
.bkwhen{display:inline-block;margin-left:8px;font-size:11.5px;font-weight:700;color:#7c7e86}
.bkcheck{margin-top:-4px}
.bkchecked{font-size:12px;color:#5b6b8c;font-weight:700}
.bkcheckerr{font-size:12px;color:#b23a26;font-weight:700}
/* Says what the button does, in the row with the button, so nobody has to guess what a
   "booked check" is. Muted, because it is an explanation and not a status. */
.bkchecknote{font-size:12px;color:#7c7e86;line-height:1.4;max-width:640px}

/* A recurring row you can open. Only lesson slots carry it — programs come from Program Sessions
   and have no editor here, so they deliberately look inert rather than clickable-but-dead. */
.bkrow.bkedit{cursor:pointer}
.bkrow.bkedit:hover{background:#f7f9fd;box-shadow:0 1px 0 rgba(0,45,120,.12)}

/* The PlayByPoint to-do list. Sits above the booking checklist because these are already decided
   and merely undone — and an uncarried cancellation sells a court twice. */
.ct-tasks{border:1px solid #f0d9c4;background:#fffaf4;border-radius:12px;padding:10px 12px;margin:0 0 14px}
.ct-tasksh{font-size:12px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;color:#9a5b16;margin-bottom:8px}
.ct-tasksh span{background:#9a5b16;color:#fff;border-radius:999px;padding:1px 7px;margin-left:6px}
.ct-task{display:flex;align-items:center;gap:10px;padding:8px 0;border-top:1px solid #f3e6d6}
.ct-task:first-of-type{border-top:0}
.ct-tag{flex:none;font-size:11px;font-weight:800;border-radius:999px;padding:2px 9px}
.ct-task.cx .ct-tag{background:#fbe4e0;color:#b23a26}
.ct-task.ch .ct-tag{background:#fdf0e2;color:#9a5b16}
.ct-tw{flex:1;min-width:0}
.ct-tm{font-size:12.5px;color:#7c7e86}
.ct-tn{font-size:12.5px;color:#5b6b8c;margin-top:2px}

/* A coach and their week. Seven boxes, one per day, because that is the shape of the question —
   "what is Amr on for" was previously assembled in the reader's head out of 197 flat rows. */
.cwk{border:1px solid #E5E7EC;border-radius:14px;background:#fff;margin:0 0 14px;overflow:hidden}
.cwkh{font-family:'Kanit',sans-serif;font-weight:800;font-size:14px;letter-spacing:.02em;
      text-transform:uppercase;color:var(--os-boast-blue,#002D78);padding:11px 14px;
      background:#f7f9fd;border-bottom:1px solid #E5E7EC;display:flex;flex-wrap:wrap;gap:10px;align-items:baseline}
.cwkh span{font-family:inherit;font-weight:600;font-size:12px;text-transform:none;letter-spacing:0;color:#7c7e86}
.cwkdays{display:grid;grid-template-columns:repeat(7,1fr);gap:1px;background:#eef1f7}
.cwkday{background:#fff;padding:8px 7px;min-height:74px}
.cwkday h5{margin:0 0 6px;font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:#9aa3b2}
.cwkday.none{background:#fcfcfd}
.cwknone{color:#c8cdd6;font-size:13px}
.cwkslot{display:block;width:100%;text-align:left;border:1px solid #dfe6f5;background:#f4f7fd;
         border-radius:9px;padding:5px 7px;margin:0 0 5px;font:inherit;cursor:pointer;line-height:1.3}
.cwkslot:hover{border-color:#002D78;background:#eaf0fc}
.cwkslot b{display:block;font-size:11.5px;color:#002D78;font-weight:800}
.cwkslot span{display:block;font-size:12px;color:#25272c;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cwkslot i{display:block;font-style:normal;font-size:11px;color:#8b93a1}
/* Three states, three colours, and the word as well — colour alone excludes anyone who does not
   separate these hues, and dies on a projector. Navy = a client has it. Amber = nobody in it, and
   that is inventory to sell. Purple = not a lesson at all and not editable here. */
.cwkslot u{display:block;text-decoration:none;font-size:9.5px;font-weight:800;letter-spacing:.08em;
           text-transform:uppercase;line-height:1.5}
.cwkslot.full{background:#f2f6fd;border-color:#c9d8f2;border-left:4px solid #002D78}
.cwkslot.full u{color:#002D78}
.cwkslot.full span{color:#16181d;font-weight:700}
.cwkslot.open{background:#fff8ee;border-color:#f0d9c4;border-left:4px solid #d9a93a}
.cwkslot.open u{color:#9a5b16}
.cwkslot.open span{color:#9a5b16;font-style:italic}
.cwkslot.prog{background:#f8f5ff;border-color:#ded3f6;border-left:4px solid #7a5bd6;cursor:default}
.cwkslot.prog u{color:#5b4a8c}
.cwkslot.prog span{color:#3f3560}
.cwkslot.prog:hover{border-color:#ded3f6;background:#f8f5ff}
/* The key, so nobody has to work the colours out from context. */
.cwkey{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;margin:0 2px 12px;font-size:12px}
.cwkey em{font-style:normal;color:#7c7e86;margin-right:6px}
.cwkeyi{font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
        border-radius:6px;padding:2px 8px;border-left:4px solid}
.cwkeyi.full{background:#f2f6fd;border-color:#002D78;color:#002D78}
.cwkeyi.open{background:#fff8ee;border-color:#d9a93a;color:#9a5b16}
.cwkeyi.prog{background:#f8f5ff;border-color:#7a5bd6;color:#5b4a8c}
@media(max-width:900px){ .cwkdays{grid-template-columns:repeat(2,1fr)} .cwkday{min-height:0} }

/* The week the coach view is showing, and the clashes in it. Both exist because the fall runs in
   two blocks: showing the whole term at once stacked September's slots on November's. */
.cwnav{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:0 2px 12px}
.cwnav b{font-family:'Kanit',sans-serif;font-size:14px;color:var(--os-boast-blue,#002D78)}
.cwnavnote{font-size:12px;color:#7c7e86;flex:1 1 320px;min-width:220px}
.cwclash{border:1px solid #f0c4bd;background:#fdf3f1;border-radius:12px;padding:10px 13px;margin:0 2px 12px;font-size:12.5px;color:#8c2f1d}
.cwclash b{color:#b23a26}
.cwclash ul{margin:6px 0 0;padding-left:18px}
.cwclash li{margin:2px 0}
.cwclash i{display:block;margin-top:4px;color:#a56b5e}
.cwkslot.clash{box-shadow:0 0 0 2px #e8b4aa inset}
.cwx{display:block;font-style:normal;font-size:9.5px;font-weight:800;letter-spacing:.08em;
     text-transform:uppercase;color:#b23a26;margin-top:1px}

/* Add a slot from an empty day, and the verdict the server gives back before anything is saved. */
.cwkadd{display:block;width:100%;border:1px dashed #d3dcec;background:none;border-radius:9px;
        padding:4px 6px;margin:0 0 6px;font:inherit;font-size:11px;font-weight:800;letter-spacing:.04em;
        text-transform:uppercase;color:#9aa3b2;cursor:pointer}
.cwkadd:hover{border-color:#002D78;color:#002D78;background:#f5f8fe}
.sp-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:10px 0}
.sp-row .lbl{margin:0}
.sp-verdict{border-radius:10px;padding:9px 11px;font-size:12.5px;margin-top:6px}
.sp-verdict.good{background:#eaf5ee;color:#1c6b39;border:1px solid #cbe4d5}
.sp-verdict.ask{background:#fff8ee;color:#8a5a12;border:1px solid #f0d9c4}
.sp-verdict.bad{background:#fdf3f1;color:#8c2f1d;border:1px solid #f0c4bd}
.sp-verdict.muted{background:#f4f6fa;color:#7c7e86;border:1px solid #e6eaf2}

/* Taking an hour, or moving one. Same three verdicts the desk sees, same colours, because a coach
   ringing to ask "what does amber mean" is the failure this is trying to avoid. */
.sp-row label{margin:0;font-size:12px;font-weight:700;color:#7c7e86}
.sp-row input,.sp-row select{padding:8px 10px;font-size:14px}
/* Asked for, not yet given. Dashed, so it reads as provisional at a glance rather than needing
   the label to be read. */
.cwkslot.pend{background:#fbfbfd;border:1px dashed #c9cfdb;border-left:4px solid #b6bdcb}
.cwkslot.pend u{color:#7c7e86}
.cwkslot.pend span,.cwkslot.pend b{color:#7c7e86}
.cwkadd{display:block;width:100%;margin-top:6px;border:1px dashed #d6dbe6;background:#fff;
        border-radius:9px;padding:6px;font-size:11px;font-weight:800;letter-spacing:.04em;
        color:#8b93a1;cursor:pointer}
.cwkadd:hover{border-color:#002D78;color:#002D78;background:#f6f9ff}
/* A court a coach took and the desk has not mirrored yet. Green rather than the corrections'
   red and amber, because nothing is wrong — somebody is just waiting on you. */
.ct-task.cb{background:#f3faf5;border-color:#cbe4d5}
.ct-task.cb .ct-tag{background:#1c6b39;color:#fff}
/* Ours, under the building's number — a second line rather than a competing headline. */
.hdmine{display:block;margin-top:2px;font-size:11.5px;color:#7c7e86}
/* Which club a weekly slot is at. Two clubs, two colours, so a coach's week can be scanned
   instead of read — and so "ct 3" is never ambiguous between two buildings that both have one. */
.cwkslot .cwclub{display:inline-block;margin-right:6px;padding:0 5px;border-radius:5px;
  border:1px solid;font-weight:800;font-size:9.5px;letter-spacing:.06em;text-transform:uppercase}
.cwkslot .cwclub.fidi{background:#eaf0fc;border-color:#c3d3f2;color:#002D78}
.cwkslot .cwclub.bp{background:#e9f5f1;border-color:#bfe0d5;color:#16403e}
.cwkslot .cwclub.oth{background:#f4f6fa;border-color:#e0e5ee;color:#7c7e86}
.cwboth{margin:-8px 0 8px;padding:6px 10px;border-radius:8px;background:#fff8ee;
  border:1px solid #f0d9c4;color:#9a5b16;font-size:11.5px;font-weight:600}
.cwkeyi.pend{background:#fbfbfd;border-color:#b6bdcb;color:#7c7e86}
/* Looking at a club that is not yours. A statement, not a warning — nothing is wrong. */
.cgnote{font-size:11.5px;color:#9a5b16;background:#fff8ee;border:1px solid #f0d9c4;
  border-radius:8px;padding:3px 9px;white-space:nowrap}
/* "What can the API do today" — a question with a date on it, so it is asked rather than assumed. */
.pbpcap{border:1px solid #E5E7EC;border-radius:12px;background:#fff;padding:12px 14px;margin:0 0 14px}
.pbpcap-h{font-size:14px;padding:8px 10px;border-radius:9px;margin-bottom:10px}
.pbpcap-h.open{background:#eaf5ee;border:1px solid #cbe4d5;color:#1c6b39}
.pbpcap-h.shut{background:#f4f6fa;border:1px solid #e6eaf2;color:#5c5f68}
.pbpcap-s{font-size:12.5px;color:#5c5f68}
.pbpcap-list{margin-top:6px;line-height:2}
.pbpcap-list code{background:#f4f6fa;border:1px solid #e6eaf2;border-radius:5px;padding:2px 6px;font-size:11px;color:#25272c}
.pbpnew{color:#1c6b39;font-weight:700}
.pbplost{color:#8c2f1d;font-weight:700}
.pbpcap-t{margin:12px 0 6px;font-family:'Kanit',sans-serif;font-weight:800;font-size:12px;
  letter-spacing:.06em;text-transform:uppercase;color:#7c7e86}
.pbprow{display:flex;gap:10px;align-items:flex-start;padding:7px 0;border-top:1px solid #f0f2f6}
.pbprow i{display:block;font-style:normal;font-size:11.5px;color:#7c7e86}
.pbprow small{display:block;font-size:11px;color:#9aa3b2;margin-top:2px}
.pbpv{flex:0 0 58px;text-align:center;font-size:9.5px;font-weight:800;letter-spacing:.06em;
  text-transform:uppercase;border-radius:6px;padding:3px 0;margin-top:2px}
.pbprow.yes .pbpv{background:#eaf5ee;color:#1c6b39}
.pbprow.no .pbpv{background:#f4f6fa;color:#9aa3b2}
/* Exactly what goes over the wire, shown before it goes. */
.pwpre{background:#0f1420;color:#d7e2f5;border-radius:9px;padding:10px 12px;font-size:11px;
  line-height:1.5;overflow:auto;max-height:280px;margin:6px 0 0;white-space:pre-wrap;word-break:break-word}
/* Week navigation on the recurring board. Copied from the desk's, because the two boards are the
   same board and drifting apart is how a coach and the desk end up looking at different Tuesdays. */
.cwnav .rnd{border-radius:999px;min-width:32px}
.cwnav input[type=date]{padding:6px 9px;font-size:13px}
/* The one date box on My week. Without a width it stretched the full row and pushed the calendar
   icon to the far right of the screen — a 10-character value in a 1200px control. */
.cwnav #cwWeekInp{flex:0 0 auto;width:170px;max-width:100%;border:1px solid var(--line);border-radius:10px}
/* The Academy, made of things you can press. Every rule here exists because a row that looks
   inert gets read and left alone — which is how a screen full of correct numbers ends up being
   the screen nobody opens. */
.jarow{cursor:pointer;border-radius:10px;transition:background .12s,box-shadow .12s}
.jarow:hover{background:#f6f9ff;box-shadow:inset 3px 0 0 #002D78}
.jacchips{display:flex;flex-wrap:wrap;gap:6px;margin:2px 0 4px}
.jacchip{display:inline-flex;align-items:center;gap:6px;border:1px solid #c3d3f2;background:#eaf0fc;
  color:#002D78;border-radius:999px;padding:4px 10px;font-size:12px;font-weight:700;cursor:pointer}
.jacchip i{font-style:normal;font-size:14px;line-height:1;opacity:.55}
.jacchip:hover{background:#fdeaea;border-color:#f0c4bd;color:#8c2f1d}
.jacchip:hover i{opacity:1}
.jacplaces{display:grid;grid-template-columns:repeat(auto-fill,minmax(168px,1fr));gap:8px;margin:2px 0 4px}
.jacplace{text-align:left;border:1px solid #E5E7EC;background:#fff;border-radius:10px;padding:8px 10px;cursor:pointer;
  transition:border-color .12s,background .12s,transform .06s}
.jacplace:hover{border-color:#002D78;background:#f6f9ff}
.jacplace:active{transform:translateY(1px)}
.jacplace b{display:block;font-size:12.5px;color:#002D78}
.jacplace i{display:block;font-style:normal;font-size:11px;color:#8b93a1;margin-top:1px}
.jacplace u{display:inline-block;text-decoration:none;margin-top:4px;font-size:9.5px;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;border-radius:5px;padding:1px 6px;background:#eaf5ee;color:#1c6b39}
.jacplace.full u{background:#fdf3f1;color:#8c2f1d}
.jacplace.in{border-color:#1c6b39;background:#f3faf5}
.jacplace.in b:after{content:' ✓';color:#1c6b39}
.jacstat{display:flex;flex-wrap:wrap;gap:6px;margin:2px 0 4px}
.jacst{border:1px solid #E5E7EC;background:#fff;border-radius:999px;padding:5px 11px;font-size:12px;
  font-weight:600;color:#5c5f68;cursor:pointer;transition:border-color .12s,background .12s}
.jacst:hover{border-color:#002D78;color:#002D78;background:#f6f9ff}
.jacst.on{background:#002D78;border-color:#002D78;color:#fff}
.jacmail{display:flex;flex-wrap:wrap;gap:6px;margin:2px 0 6px}
.jacmailout{border:1px solid #E5E7EC;border-radius:11px;padding:10px 12px;background:#fbfcfe;margin-top:6px}
.jacmailh{font-size:12px;color:#5c5f68}
.jacmailsub{font-weight:700;font-size:13px;color:#002D78;margin:4px 0 6px}
.jacmailout textarea{width:100%;font-size:12.5px;line-height:1.55;font-family:inherit}
.jacmailacts{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:8px}
.jacmailacts .hint{font-size:11.5px;color:#8b93a1}

/* ---- Junior Academy, coach side (read-only) ------------------------------------------------
   Filter bar, class rows and rosters. Kept here rather than inline so the desk's copy of this
   stylesheet can carry the same rules — test-shared-files.js requires every line of the coaches
   sheet to exist in the desk's, which is what stops the two drifting. */
.jabar{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin:0 2px 12px}
.jabl{font-size:11.5px;color:#98a1ad;font-weight:700;margin-left:6px}
.jabar .pill{font-size:12px;padding:5px 10px;border-radius:999px;font-weight:700}
.jabar input{flex:1;min-width:150px;padding:7px 11px;border:1px solid #E5E7EC;border-radius:999px;font-size:13px;font-family:inherit}
.jaclass{background:#fff;border:1px solid #E5E7EC;border-radius:14px;margin:0 2px 8px;cursor:pointer}
.jaclass.open{border-color:#c8d3ea}
.jach{display:flex;gap:10px;align-items:flex-start;padding:12px 14px}
.jan{font-size:14px;font-weight:700;color:#002D78;line-height:1.3}
.jam{font-size:12px;color:#7c7e86;margin-top:3px}
.jabarline{height:7px;border-radius:999px;background:#eef1f6;overflow:hidden;margin-top:8px}
.jabarline i{display:block;height:7px}
.jacount{text-align:right;min-width:74px}
.jacount b{display:block;font-weight:800;font-size:19px;color:#002D78;line-height:1}
.jacount .pill{margin-top:4px;font-size:11px;padding:3px 8px}
.jaroster{border-top:1px solid #eef1f6;padding:8px 14px 12px}
.jakid{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:0;
  border-bottom:1px solid #f2f4f8;padding:9px 0;font-family:inherit;font-size:13.5px;color:#2f2626;cursor:pointer}
.jakid:last-child{border-bottom:0}
.jakid b{font-weight:700;color:#002D78}
.jaalso{display:block;font-size:11.5px;color:#98a1ad;margin-top:2px}
.jaarrow{font-size:11.5px;color:#98a1ad;font-weight:700;white-space:nowrap}

/* ---- My week: the coach's whole week on the weekly board ------------------------------------
   The board carries dated things now — lessons, clinics, requests — beside the weekly courts.
   Three states the desk's copy never needed:
     .prog.tap  a program IS tappable here (check in / can't make it), unlike on the desk's board
                where it is reference only, so the pointer comes back
     .cover     up for grabs — another coach may take it, and it must not read as booked
     .done      checked in, hours counted, nothing left to do */
.cwkslot.prog.tap{cursor:pointer}
.cwkslot.prog.tap:hover{border-color:#7a5bd6;background:#f3eeff}
.cwkslot.cover{background:#fdeeee;border-color:#f3cdcd;border-left:4px solid #d05252}
.cwkslot.cover u{color:#a33232}
.cwkslot.cover span{color:#8f3030}
.cwkslot.done{opacity:.62}
.cwkslot.done u{color:#1c7a4a}

/* ---- "something is loading" ------------------------------------------------------------------
   A two-pixel bar across the very top, on whenever any request is in flight. It is deliberately
   not a spinner in the middle of the screen: most loads here happen while a usable screen is
   already drawn, and covering it up to say so makes the app feel slower than it is. The stripe
   travels rather than filling, because we cannot honestly say how far along a request is. */
#apiBar{position:fixed;top:0;left:0;right:0;height:3px;z-index:400;pointer-events:none;
  background:transparent;overflow:hidden;opacity:0;transition:opacity .18s ease}
#apiBar.on{opacity:1}
#apiBar i{display:block;height:100%;width:36%;border-radius:0 3px 3px 0;
  background:linear-gradient(90deg,rgba(0,45,120,0) 0%,#002D78 35%,#4caf7d 100%);
  animation:apiSlide 1.05s cubic-bezier(.62,.03,.35,.98) infinite}
@keyframes apiSlide{0%{transform:translateX(-100%)}100%{transform:translateX(380%)}}
@media (prefers-reduced-motion:reduce){
  #apiBar i{animation:none;width:100%;opacity:.55}
}
/* ---- Loading: the ball ----------------------------------------------------------------------
   Seth, 7 Aug: "honestly for now I think let's drop the player and can we just use like a bouncing
   double dot squash ball across the screen while it loads?"

   Which is better than what it replaced. The drawn player was a stick figure trying to be a
   photograph; a double-yellow-dot ball is the actual object, it is unmistakably squash to anyone
   who plays, and it carries no likeness and no footage rights.

   Four nested elements rather than one, because four transforms have to run on different clocks
   and they cannot share a `transform` property:
     .osbx    travels out and back    2.2s
     .osby    falls and rises          .55s, alternating — so a full bounce is 1.1s
     .osbs    flattens on contact     1.1s
     .osbsvg  spins, so the dots tumble
   The squash sits at 0%/100% of its cycle and NOT at 50%: .osby alternates over half the period,
   so 50% is the apex — the one moment nothing is touching the ball. Putting the flatten there
   (which is where it went first) makes it pop at the top of its arc like a balloon. */
.osload{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;
  padding:38px 20px;text-align:center;min-height:min(44vh,340px)}
.osload.sm{padding:16px 12px;min-height:0;gap:9px}
.osload .oscap{font-size:13.5px;font-weight:600;color:#5a6270;letter-spacing:.01em}
.osload .ossub{font-size:12px;color:#98a1ad;margin-top:-8px;max-width:280px}
.osload .osfig{width:170px;height:128px;display:block;object-fit:contain}
.osblane{position:relative;width:230px;height:74px}
.osload.sm .osblane{width:150px;height:52px}
.osbx{position:absolute;left:0;top:0;width:30px;height:100%;animation:osbX 2.2s linear infinite}
.osload.sm .osbx{width:20px}
.osby{position:absolute;left:0;bottom:11px;width:100%;animation:osbY .55s cubic-bezier(.33,0,.66,1) infinite alternate}
.osbs{width:100%;transform-origin:50% 100%;animation:osbSquash 1.1s linear infinite}
.osbsvg{display:block;width:100%;height:auto;animation:osbSpin 2.2s linear infinite}
.osbfloor{position:absolute;left:0;right:0;bottom:9px;height:2px;border-radius:2px;background:#e6eaf1}
.osbsh{position:absolute;bottom:6px;left:1px;width:28px;height:6px;border-radius:50%;
  background:#0f1c3a;opacity:.16;animation:osbShadow 1.1s cubic-bezier(.33,0,.66,1) infinite}
.osload.sm .osbsh{width:19px;height:5px}
@keyframes osbX{0%{transform:translateX(0)}50%{transform:translateX(200px)}100%{transform:translateX(0)}}
@keyframes osbY{from{transform:translateY(0)}to{transform:translateY(-38px)}}
@keyframes osbSquash{
  0%{transform:scale(1.26,.74)}7%{transform:scale(1,1)}
  93%{transform:scale(1,1)}100%{transform:scale(1.26,.74)}
}
@keyframes osbSpin{from{transform:rotate(0)}to{transform:rotate(360deg)}}
@keyframes osbShadow{
  0%{transform:scaleX(1);opacity:.20}50%{transform:scaleX(.5);opacity:.06}100%{transform:scaleX(1);opacity:.20}
}
/* On navy — the sign-in screens. The ball is already dark, so only its surroundings invert. */
.osload.navy .oscap{color:#cdd8ee}
.osload.navy .ossub{color:#9fb2d8}
.osload.navy .osbfloor{background:rgba(255,255,255,.22)}
.osload.navy .osbsh{background:#000;opacity:.24}
/* Somebody who has asked their machine to stop moving things gets the ball parked mid-court
   rather than a frozen mid-bounce that reads as a rendering fault. */
@media (prefers-reduced-motion:reduce){
  .osbx,.osby,.osbs,.osbsvg,.osbsh{animation:none}
  .osbx{transform:translateX(100px)}
}

/* ---- Junior Academy · registration ----------------------------------------------------------
   Seth, 7 Aug: "the registration piece especially is useless… it needs to be way more organized".

   The screen is now grouped by the next move rather than by status, so these are the parts of a
   worklist: a thin progress line (context, not the job), the funnel as filters, and one bordered
   group per move with the reason written into the header. The left border colour is the only
   thing carrying stage — everything else stays quiet so the names read. */
.jarprog{display:flex;align-items:center;gap:12px;margin:0 0 12px;
  font-size:12.5px;color:#7c7e86;font-weight:600}
.jarprog>span{flex:0 0 auto}
.jarprog>div{flex:1 1 auto;margin-top:0}
.jartiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:8px;margin-bottom:12px}
.jartile{appearance:none;text-align:left;cursor:pointer;font:inherit;
  background:#fff;border:1px solid #E5E7EC;border-top:3px solid #c9d0e0;border-radius:12px;
  padding:9px 11px 10px;transition:box-shadow .12s ease,border-color .12s ease}
.jartile:hover{box-shadow:0 2px 10px rgba(15,28,58,.08)}
.jartile.on{border-color:#002D78;box-shadow:0 0 0 2px rgba(0,45,120,.14)}
.jartile b{display:block;font-size:19px;font-weight:800;color:#002D78;line-height:1.1}
.jartile span{display:block;font-size:11.5px;color:#7c7e86;margin-top:3px;font-weight:600;line-height:1.25}
.jarchips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 14px}
.jarlbl{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:#98a1ad;font-weight:700;margin-right:2px}
.jarchips .chip{appearance:none;cursor:pointer;font:inherit;font-size:12.5px;font-weight:600;
  background:#fff;border:1px solid #E5E7EC;color:#5a5f68;border-radius:999px;padding:5px 11px}
.jarchips .chip:hover{border-color:#c3cbd8}
.jarchips .chip.on{background:#002D78;border-color:#002D78;color:#fff}
.jarchips .chip b{margin-left:5px;opacity:.8}
.jargrp{border-left:4px solid #c9d0e0;border-radius:0 12px 12px 0;background:#fff;
  border-top:1px solid #E5E7EC;border-right:1px solid #E5E7EC;border-bottom:1px solid #E5E7EC;
  margin-bottom:12px;overflow:hidden}
.jarhead{display:grid;grid-template-columns:14px auto auto 1fr;align-items:center;gap:8px;
  width:100%;appearance:none;cursor:pointer;font:inherit;text-align:left;
  background:#fafbfd;border:0;border-bottom:1px solid #EEF1F6;padding:11px 14px}
.jargrp.shut .jarhead{border-bottom:0}
.jarhead:hover{background:#f4f7fb}
.jarcar{color:#98a1ad;font-size:12px}
.jarttl{font-weight:700;font-size:14px;color:#1B1F24}
.jarn{font-weight:800;font-size:12px;color:#fff;background:#002D78;border-radius:999px;padding:1px 8px}
.jarsub{font-size:12px;color:#8a919c;font-weight:500;line-height:1.35}
@media (max-width:820px){
  .jarhead{grid-template-columns:14px auto auto;row-gap:4px}
  .jarsub{grid-column:1 / -1}
}
.jargrp .jarow{border-left:0;border-right:0;border-radius:0;margin:0}
.jargrp .jarow:last-child{border-bottom:0}
.jarask{color:#8a6d1f;margin-top:3px}
/* The Academy filter chips fold away behind one button — see jaBars(). The row keeps its own
   wrapping so the search box and the toggle stay on the first line on a phone. */
.jabarrow{display:flex;flex-wrap:wrap;align-items:center;gap:6px;width:100%;margin-top:8px;
  padding-top:8px;border-top:1px solid #EEF1F6}

/* ---- Lesson request sheet ------------------------------------------------------------------
   The client's ask, said next to the fields it constrains. It is the sentence the desk is trying
   to satisfy, so it reads as prose rather than as another labelled field. */
.rq-askline{font-size:12.5px;color:#6b7280;margin:8px 2px 0;line-height:1.45}
.rq-askline b{color:#1B1F24}
/* The held-court row that matches the time already in the form. One of these is an answer; the
   rest are options. */
.slotrow.on{border-color:#1c7a4a;box-shadow:0 0 0 2px rgba(28,122,74,.16)}
/* The fact table used to live inside <details>. Open, it needs to read as a block of information
   rather than as a form — two columns on a wide screen, one on a narrow one. */
.lr-facttable.open{display:grid;grid-template-columns:1fr 1fr;gap:2px 18px;margin:2px 0 4px}
@media (max-width:760px){ .lr-facttable.open{grid-template-columns:1fr} }
