  /* BehaviorDash brand palette (approved). Green/Red here are the
     darkened, text-safe forms of Dash Green/Eye Coral - both fail WCAG
     white-text contrast as solid fills, so every use in this file is
     text-on-light-tint (message text, +/- buttons), never a solid button
     with white lettering on top. */
  :root{ --brand:#123D73; --brand2:#10243E; --ink:#10243E; --muted:#5C6B78; --line:#DCE6E3; --bg:#F4F8F7; --surface:#fff;
    --green:#4d701c; --green-bg:#f4faeb; --red:#8b2d1e; --red-bg:#fdedeb; --slate-bg:#e2e8f0; --amber:#d97706; }
  *{box-sizing:border-box}
  body{margin:0;font-family:'Poppins',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;color:var(--ink);background:var(--bg);-webkit-font-smoothing:antialiased}
  .hidden{display:none!important}
  #login{position:fixed;inset:0;background:radial-gradient(1100px 600px at 25% -10%,#123D73,#10243E);display:flex;align-items:center;justify-content:center;z-index:100}
  /* #login is fixed and centred with no overflow handling, so anything taller
     than the viewport was clipped at BOTH ends — the two-factor gate lost its
     own heading, which is how it reached production reading "continue".
     margin:auto centres when it fits and scrolls from the top when it does
     not; align-items:center alone cannot do that. */
  #login{overflow-y:auto;align-items:flex-start;padding:24px 16px}
  #login .box{background:#fff;border-radius:18px;padding:34px;width:90%;max-width:360px;box-shadow:0 30px 60px rgba(0,0,0,.4);margin:auto}

  /* ── The mandatory two-factor gate ─────────────────────────────────────
     These styles live here, not in surfaces.css, because the recorder does
     NOT load surfaces.css — that was removed deliberately after the admin
     layer bled into this surface. Without them the gate rendered completely
     unstyled: a 200px QR at intrinsic size, unformatted steps, and the setup
     key as a bare run of characters. */
  #login .box.mfa-gate{max-width:min(560px,92vw)}
  .mfa-gate__lede{margin:0 0 18px;color:var(--muted);font-size:14px;line-height:1.5}
  .sec-enroll__steps{margin:0 0 18px;padding-left:20px;color:var(--ink);font-size:14px;line-height:1.55}
  .sec-enroll__steps li{margin-bottom:6px}
  /* A white plate whatever sits behind it: a QR needs quiet margins around
     the code or a phone camera will not find it. */
  .sec-enroll__qr{display:block;width:180px;height:180px;padding:10px;background:#fff;
    border:1px solid var(--line);border-radius:10px;margin:0 auto 16px}
  .sec-enroll__key{display:flex;flex-direction:column;gap:5px;margin-bottom:18px}
  .sec-enroll__key span{font-size:12px;font-weight:700;color:var(--muted)}
  .sec-enroll__key code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
    font-size:13px;letter-spacing:.08em;color:var(--ink);padding:10px 12px;background:#F4F8F7;
    border:1px solid var(--line);border-radius:8px;overflow-wrap:anywhere;user-select:all}
  .mfa-gate__field{display:block;margin-bottom:10px}
  .mfa-gate__field input{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
    font-size:22px;letter-spacing:.3em;text-align:center}
  #login .box.mfa-gate .link-btn{display:block;width:100%;margin-top:12px;text-align:center;
    background:none;border:0;color:var(--muted);font-size:13px;cursor:pointer}

  /* Side by side once there is room, so the steps and the code are read
     together rather than the code being a scroll away. */
  @media (min-width:720px) and (min-height:620px){
    #login .box.mfa-gate .sec-enroll__qr{float:right;margin:0 0 12px 20px}
  }
  #login h2{margin:0 0 4px;font-size:20px}
  #login p{margin:0 0 16px;color:var(--muted);font-size:14px}
  #login input{width:100%;padding:12px 14px;border:1px solid var(--line);border-radius:10px;margin-bottom:10px;font-size:15px;font-family:inherit}
  #login button{width:100%;padding:13px;border:none;border-radius:10px;background:var(--brand);color:#fff;font-weight:600;font-size:15px;cursor:pointer;font-family:inherit}
  #login .err{color:var(--red);font-size:13px;min-height:16px;margin-top:6px}
  .topbar{position:sticky;top:0;z-index:20;background:#10243E;color:#fff;display:flex;align-items:center;gap:12px;padding:12px 16px}
  .topbar .brand{display:flex;align-items:center;gap:8px;font-weight:700}
  .topbar .brand .brand-icon{width:32px;height:32px;object-fit:contain;display:block;filter:drop-shadow(0 2px 3px rgba(0,0,0,.4))}
  .topbar select{margin-left:6px;padding:8px 10px;border-radius:9px;border:1px solid #1b3a5e;background:#123D73;color:#fff;font-family:inherit;font-size:14px;min-width:0;max-width:40vw}
  .topbar .spacer{margin-left:auto}
  /* Subtle, useful rather than decorative - RBTs are timestamping behavior
     in real time, so having the current time always in view earns its
     place, but it should read as quiet supporting text, same weight as the
     email next to it, not a clock-widget. */
  .topbar .clock{color:#9fb3c8;font-size:13px;white-space:nowrap;flex-shrink:0;font-variant-numeric:tabular-nums}
  /* v249 (Workstream 24): a distinct hue from .pending's amber (queue
     backlog, resolves itself) and the failed-queue's red (needs attention
     now) - this is neither. It is a plain fact about the device, and the
     app already handles it safely, so it reads as informative, not alarming. */
  .topbar .offline{color:#93c5fd;font-size:12px;white-space:nowrap;flex-shrink:0;font-weight:600}
  .topbar .pending{color:#fde68a;font-size:12px;white-space:nowrap;flex-shrink:0;font-weight:600;cursor:pointer}
  .topbar .who{color:#9fb3c8;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:160px}
  .topbar .out{background:#1b3a5e;color:#fff;border:none;border-radius:8px;padding:7px 12px;cursor:pointer;font-family:inherit;font-size:13px;flex-shrink:0}
  .topbar .feedback-open{background:transparent;color:#d5e1ec;border:1px solid #345577;border-radius:8px;padding:6px 10px;cursor:pointer;font-family:inherit;font-size:12px;font-weight:600;flex-shrink:0}
  .topbar .feedback-open:hover{background:#1b3a5e;color:#fff}
  /* Deliberately the same treatment as .feedback-open rather than a new one.
     Twelve component generations already coexist here; a thirteenth styling
     of "outlined button in the topbar" would not earn its keep. Fill and ink
     carry the hover — no accent sliver, no bracket. */
  .topbar .admin-link{background:transparent;color:#d5e1ec;border:1px solid #345577;border-radius:8px;
    padding:6px 10px;font-family:inherit;font-size:12px;font-weight:600;flex-shrink:0;
    text-decoration:none;display:inline-flex;align-items:center;white-space:nowrap;cursor:pointer}
  .topbar .admin-link:hover{background:#1b3a5e;color:#fff}
  .topbar .admin-link.hidden{display:none}
  .topbar .brand{flex-shrink:0}
  /* On narrow screens the student picker + email + sign-out don't all fit
     on one line - drop the email first since it's the least essential. */
  @media(max-width:560px){ .topbar .who{display:none} }
  @media(max-width:500px){ .topbar .feedback-open{font-size:0;padding:7px 9px}.topbar .feedback-open:after{content:"Feedback";font-size:11px} }
  @media(max-width:420px){ .brand-word{display:none} }
  .nav{display:flex;gap:4px;background:#fff;border-bottom:1px solid var(--line);padding:6px 14px;position:sticky;top:53px;z-index:15;overflow-x:auto}
  .navbtn{background:none;border:none;padding:8px 14px;border-radius:9px;font-weight:600;color:var(--muted);cursor:pointer;font-family:inherit;font-size:14px;white-space:nowrap}
  .navbtn.active{background:var(--brand);color:#fff}
  .wrap{max-width:1100px;margin:0 auto;padding:14px 16px 110px}
  /* Session toolbar: #session-bar and #plan-btn are kept as separate DOM
     elements (same ids, same event listeners as before - nothing about how
     they're wired up changes) but are grouped inside one wrapper and styled
     as a single attached strip instead of a floating detached button, since
     renderSessionBar() replaces #session-bar's innerHTML on every tick and
     must never touch #plan-btn or its listener. Kept deliberately thin - a
     one-line status strip, not a dashboard header. */
  #session-toolbar{max-width:none;margin:0 auto 10px}
  #plan-btn{display:block;width:100%;margin:0;background:#0e2f57;color:#dbe4f3;border:none;border-top:1px solid rgba(255,255,255,.14);border-radius:0 0 12px 12px;padding:7px 16px;font-weight:700;font-size:12.5px;text-align:left;cursor:pointer;font-family:inherit}
  #session-toolbar:has(#plan-btn:not(.hidden)) #session-bar{border-radius:12px 12px 0 0;margin-bottom:0}
  .empty{color:var(--muted);text-align:center;padding:50px 20px;font-size:15px}
  .muted{color:var(--muted)}
  .card{background:var(--surface);border:1px solid var(--line);border-radius:12px;padding:12px;margin-bottom:10px;box-shadow:0 1px 3px rgba(15,23,42,.05)}
  /* Collection board: a dense, high-frequency data-entry grid, not a report
     dashboard - as many targets as possible visible at once with minimal
     scrolling. Cards are now compact enough (see below) that letting each
     row stretch to match its tallest card evens the grid out into tidy
     rows instead of a jagged mix of heights, without reintroducing the big
     dead whitespace v25 had - that problem came from Task Analysis always
     rendering every step inline (making it dramatically taller than every
     other card); now that it's collapsed to just the current step by
     default, the height difference between card types is small, so
     stretching only adds a modest amount of breathing room, not a giant
     empty block. .card is a flex column so its trailing element (the
     meta line, a stat line, or the step-toggle - whichever a given type
     ends with) can be pinned to the bottom via margin-top:auto, keeping
     that row lined up across cards of slightly different content length.
     minmax(220px) + a tight gap gets roughly four cards across on a normal
     desktop width. */
  #cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px;align-items:stretch;margin-bottom:10px}
  #cards .card{margin-bottom:0;display:flex;flex-direction:column}
  #cards .card-foot{margin-top:auto;padding-top:6px}
  #cards .empty{grid-column:1/-1}
  /* Card header: name+badge is its own row, kept tight; the "View Plan"
     jump link (only present when this behavior is an active plan target) is
     a separate row below it, right-aligned, instead of being squeezed into
     the same line as the name/badge. The head-actions row collapses to
     nothing when empty, so cards with no "View Plan" link (most cards)
     don't get any extra blank space. */
  .card .head{display:flex;align-items:center;gap:6px;margin-bottom:4px}
  .card .name{font-size:14px;font-weight:600;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .card .head-actions{display:flex;justify-content:flex-end;margin:0 0 4px}
  .card .head-actions:empty{display:none}
  .badge{display:inline-flex;align-items:center;flex-shrink:0;font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--brand);background:#eef2ff;padding:2px 7px;border-radius:999px;white-space:nowrap}
  .badge.interval{color:#0e7490;background:#ecfeff}
  .badge.duration{color:var(--amber);background:#fff7ed}
  .badge.rate{color:#7c3aed;background:#f5f3ff}
  .badge.latency{color:#9a3412;background:#fff7ed}
  .badge.trial{color:#166534;background:#f0fdf4}
  .badge.task_analysis{color:#9d174d;background:#fdf2f8}
  .badge.scale{color:#0369a1;background:#f0f9ff}
  .big.prompt{background:#fef3c7;color:#92400e}
  /* Task Analysis: compact by default - only the current/next unscored step
     (.ta-current) is shown, with a small toggle to expand the full list
     when staff need to jump to a different step (e.g. to correct one they
     already scored). A hairline divider between rows once expanded, so a
     long list still reads as distinct rows rather than a run-on block. */
  .step-row{padding:4px 0 8px;border-bottom:1px solid #eef2f7}
  .step-row .step-label{font-size:12px;margin-bottom:4px;font-weight:500}
  .ta-steps.ta-collapsed .step-row{display:none}
  .ta-steps.ta-collapsed .step-row.ta-current{display:block;border-bottom:none;padding-bottom:0}
  .ta-progress{margin:0 0 6px;text-align:left;font-size:11.5px}
  .ta-toggle{margin-top:auto;padding-top:6px;font-size:11px;color:var(--brand);font-weight:600;cursor:pointer;text-align:right}
  /* Rate card: the timer + start/stop toggle are visually grouped as their
     own sub-block, separated (by a thin divider, not extra whitespace) from
     the tally count above, since they are a related-but-distinct control
     (timing observation windows) rather than part of the same +/- tally
     interaction. */
  .timer-block{margin-top:8px;padding-top:8px;border-top:1px solid #eef2f7}
  .abc-entry{padding:8px 0;border-bottom:1px solid #eef2f7;font-size:13px}
  .abc-entry .when{color:var(--muted);font-size:11px}
  .count{font-size:30px;font-weight:700;text-align:center;line-height:1;margin:2px 0 8px}
  /* v220. The count is a button now, but it must still READ as the number it
     always was - no button chrome, no border, no fill. It is the affordance,
     not a control that happens to sit near one. Inherits .count for size and
     weight, then strips everything a <button> brings with it. */
  .count-editable{display:block;width:100%;background:none;border:0;padding:6px 0;
    color:inherit;font-family:inherit;cursor:pointer;
    /* A 44px target on a number that is only ~30px tall: the padding is the
       touch area, not decoration. */
    min-height:44px}
  .count-editable:hover:not(:disabled){background:var(--slate-bg);border-radius:10px}
  .count-editable:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:10px}
  .count-hint{color:var(--muted);font-size:11px}
  /* The in-place editor. Deliberately not a modal: the recorder is mid-session
     and a dialog would cost a dismiss gesture and the context around it. */
  .count-edit{margin:2px 0 8px;display:flex;flex-direction:column;gap:8px}
  .count-input{width:100%;text-align:center;font-size:30px;font-weight:700;line-height:1;
    padding:8px 6px;border:2px solid var(--brand);border-radius:10px;
    font-family:inherit;color:var(--ink);background:var(--surface);
    /* iOS zooms the page when a focused input is under 16px. 30px is safe and
       is also simply the size the number already was. */
    font-variant-numeric:tabular-nums}
  .count-input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px rgba(18,61,115,.15)}
  .count-input-bad{border-color:var(--red)}
  .count-edit-actions{display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:stretch}
  .count-edit-actions .count-set{min-height:44px}
  .count-edit-actions .small{min-height:44px;padding-left:14px;padding-right:14px}
  .btn-row{display:flex;gap:6px}
  .big{flex:1;border:none;border-radius:10px;padding:9px;font-size:14.5px;font-weight:700;cursor:pointer;font-family:inherit;transition:filter .1s;min-height:40px;display:flex;align-items:center;justify-content:center}
  .big:active{filter:brightness(.94)}
  .big.primary{background:var(--brand);color:#fff}
  .big.plus{background:var(--green-bg);color:var(--green)}
  .big.minus{background:var(--red-bg);color:var(--red)}
  .big.null{background:var(--slate-bg);color:#475569}
  .small{flex:0 0 auto;border:1px solid var(--line);background:#fff;border-radius:10px;padding:7px 12px;min-height:38px;font-size:13.5px;font-weight:700;cursor:pointer;font-family:inherit;color:var(--muted);display:flex;align-items:center;justify-content:center}
  .sub{margin-top:6px;color:var(--muted);font-size:12px;text-align:center}
  .sub-tight{margin-top:-4px}
  .sub b{color:var(--ink);font-size:13px}
  /* Interval recording (v200). The header sits ABOVE the score buttons and
     the countdown is tabular, so nothing reflows or shifts under a thumb as
     the seconds tick down - the buttons stay exactly where they were for the
     whole session. */
  .int-head{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;
    margin:2px 0 6px;padding-bottom:6px;border-bottom:1px solid #eef2f7}
  .int-head.done{opacity:.72}
  .int-slot{font-size:13px;font-weight:700;color:var(--ink)}
  .int-clock{font-size:13px;font-weight:700;color:var(--brand);
    font-variant-numeric:tabular-nums;margin-left:auto}
  .int-method{flex:0 0 100%;font-size:11px;color:var(--muted)}
  .int-scored{font-size:11px;font-weight:700;color:var(--green);
    background:var(--green-bg);border-radius:5px;padding:1px 6px}
  .int-prompt{font-size:11.5px;color:var(--muted);margin:0 0 7px;line-height:1.35}
  /* NOT var(--amber) — #d97706 measures 3.19:1 on the card and this is small
     text, so it needs the darkened form to clear 4.5:1. */
  .int-gap{color:#b45309}
  .int-legacy{color:var(--muted);font-style:italic}
  /* Observation context (v202). State is carried by ink and fill only - no
     corner accents, no edge slivers. */
  .obs-foot{margin-top:6px;font-size:11.5px;color:var(--muted);text-align:center;line-height:1.35}
  .obs-why{color:#b45309}
  .obs-zero-row{margin-top:6px;justify-content:center}
  .obs-zero{flex:1 1 auto;justify-content:center}
  .obs-zero.is-on{background:var(--green-bg);color:var(--green);border-color:#c4dda0;font-weight:700}
  /* v204. Scale anchors and duration boundary. State by fill and ink only. */
  .scale-anchor-current{color:var(--brand);font-weight:600}
  .scale-anchors{margin-top:8px;padding-top:7px;border-top:1px solid #eef2f7;
    display:flex;flex-direction:column;gap:3px;font-size:11.5px;color:var(--muted);line-height:1.35}
  .scale-anchor b{color:var(--ink);font-weight:700;margin-right:4px;font-variant-numeric:tabular-nums}
  /* An unanchored scale states the limitation rather than implying the
     numbers are defined. #b45309 not var(--amber): the token measures
     3.19:1 and this is small text. */
  .scale-unanchored{color:#b45309;font-style:italic}
  .btn-row .small.is-scored{background:var(--brand);color:#fff;border-color:var(--brand);font-weight:700}
  .dur-eps{margin-top:6px;font-size:11.5px;color:var(--muted);text-align:center;font-variant-numeric:tabular-nums}
  .dur-boundary{margin-top:3px;font-size:11px;color:var(--muted);text-align:center}
  /* The already-scored state is carried by a deeper fill and heavier ink -
     never an outline, a corner marker or an edge sliver. The tints stay light
     because the brand green and red both fail white-text contrast as solid
     fills (see the palette note at the top of this file). */
  .big.is-scored{font-weight:800}
  .big.plus.is-scored{background:#dbeec0;color:#3c5916}
  .big.minus.is-scored{background:#f8cfc8;color:#6f2417}
  .big.null.is-scored{background:#cbd5e1;color:#334155}
  .big:disabled{opacity:.5;cursor:default}
  .timer{font-size:28px;font-weight:700;text-align:center;font-variant-numeric:tabular-nums;margin:2px 0 8px}
  textarea{width:100%;border:1px solid var(--line);border-radius:12px;padding:12px 14px;font-family:inherit;font-size:15px;min-height:80px;resize:vertical;outline:none}
  textarea:focus{border-color:var(--brand);box-shadow:0 0 0 3px rgba(18,61,115,.15)}

  /* v61: non-clinical pilot feedback dialog. */
  .feedback-modal{position:fixed;inset:0;background:rgba(15,23,42,.56);z-index:90;display:flex;align-items:center;justify-content:center;padding:20px}
  .feedback-dialog{background:#fff;border-radius:16px;max-width:560px;width:100%;max-height:88vh;overflow:auto;padding:22px 24px;box-shadow:0 24px 64px rgba(15,23,42,.34)}
  .feedback-dialog-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
  .feedback-kicker{text-transform:uppercase;letter-spacing:.075em;color:var(--brand);font-size:9.5px;font-weight:800}
  .feedback-title{font-size:19px;font-weight:700;margin-top:2px}
  .feedback-help{font-size:12.5px;line-height:1.5;color:var(--muted);background:#f7f9fa;border:1px solid var(--line);border-radius:9px;padding:9px 11px;margin:14px 0}
  .feedback-field{display:flex;flex-direction:column;gap:5px;color:var(--muted);font-size:11.5px;font-weight:600;margin-top:11px}
  .feedback-field select{width:100%;border:1px solid var(--line);border-radius:10px;padding:10px 12px;font:14px inherit;background:#fff;color:var(--ink)}
  .feedback-field textarea{min-height:120px;color:var(--ink);font-size:14px;font-weight:400}
  .feedback-submit-row{display:flex;align-items:center;gap:12px;margin-top:13px}
  .feedback-submit-row .submitbtn{width:auto;min-width:140px;margin:0}
  .feedback-output{font-size:12px;color:var(--muted)}
  .feedback-output.error{color:var(--red)}
  .feedback-output.ok{color:var(--green);font-weight:600}
  .feedback-output.warning{color:#92400e;font-weight:600}
  @media(max-width:560px){.feedback-dialog{padding:18px}.feedback-submit-row{align-items:flex-start;flex-direction:column}.feedback-submit-row .submitbtn{width:100%}}
  .flagrow{display:flex;align-items:center;gap:8px;margin-top:12px;font-size:14px;color:#b45309;font-weight:600;cursor:pointer}
  .hform{display:grid;grid-template-columns:repeat(2,1fr);gap:10px}
  .hform label{display:flex;flex-direction:column;font-size:12px;color:var(--muted);gap:4px}
  .hform input,.hform select{padding:10px;border:1px solid var(--line);border-radius:9px;font-family:inherit;font-size:14px}
  .attest{display:flex;align-items:center;gap:8px;margin-top:14px;font-size:14px;cursor:pointer}
  .attest.foot{margin:0;font-size:13px;color:var(--muted)}
  .submitbtn{margin-top:14px;width:100%;background:var(--brand);color:#fff;border:none;border-radius:10px;padding:13px;font-weight:700;font-size:15px;cursor:pointer;font-family:inherit}
  .title{font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin:0 0 10px;font-weight:600}
  .footer{position:fixed;left:0;right:0;bottom:0;background:#fff;border-top:1px solid var(--line);padding:12px 16px;box-shadow:0 -2px 10px rgba(15,23,42,.06)}
  /* space-between anchors status text to the left edge and the primary
     action to the right edge of the bar - a conventional bottom-bar split,
     instead of the pair packing together and floating in the middle of the
     wide bar. */
  .footer .wrapf{max-width:1100px;margin:0 auto;width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px}
  .footer .attest{margin:0;flex:1}
  .footer .status{color:var(--muted);font-size:13px;white-space:nowrap}
  .footer button{background:var(--brand);color:#fff;border:none;border-radius:12px;padding:13px 20px;font-size:15px;font-weight:700;cursor:pointer;font-family:inherit}

  /* ---- Active Session workspace additions ---- */
  .card{box-shadow:0 2px 8px rgba(16,36,62,.07)}
  #cards .card{transition:box-shadow .15s,transform .15s}
  #cards .card:hover{box-shadow:0 6px 18px rgba(16,36,62,.11);transform:translateY(-1px)}
  .big{box-shadow:0 2px 6px rgba(16,36,62,.1)}
  .big.primary{box-shadow:0 3px 10px rgba(18,61,115,.28)}
  #session-bar{max-width:none;margin:0 auto 0;background:linear-gradient(135deg,#10243E,#123D73);color:#fff;border-radius:12px;padding:9px 16px;box-shadow:0 4px 14px rgba(16,36,62,.18);display:flex;flex-wrap:wrap;align-items:center;gap:4px 14px}
  #session-bar .live-dot{width:8px;height:8px;border-radius:50%;background:#8CCB32;box-shadow:0 0 0 0 rgba(140,203,50,.6);animation:pulse 2s infinite}
  @keyframes pulse{0%{box-shadow:0 0 0 0 rgba(140,203,50,.55)}70%{box-shadow:0 0 0 7px rgba(140,203,50,0)}100%{box-shadow:0 0 0 0 rgba(140,203,50,0)}}
  #session-bar .sb-title{font-weight:700;font-size:13.5px;display:flex;align-items:center;gap:7px}
  #session-bar .sb-meta{font-size:11.5px;color:#c3d2e2;display:flex;flex-wrap:wrap;gap:4px 10px;margin-left:auto}
  #session-bar .sb-meta b{color:#fff;font-weight:600}
  /* Visual separators between meta pieces (Started / elapsed / Phase /
     Autosave) so the bar reads as distinct pieces of information instead of
     one run-on sentence - purely a CSS ::before dot, no change to the text
     content generated in renderSessionBar(). */
  #session-bar .sb-meta span:not(:first-child)::before{content:"•";margin-right:10px;opacity:.45}
  .glance{max-width:660px;margin:0 auto 14px;background:var(--surface);border:1px solid var(--line);border-radius:16px;padding:16px 18px;box-shadow:0 2px 8px rgba(16,36,62,.07)}
  /* Session-at-a-glance tiles, restyled away from the old "tab-like" blue
     top-stripe treatment toward a restrained, Apple-inspired surface: a
     gentle tonal lift off the parent card, a hairline border instead of a
     heavy outline, a soft shadow for separation, and a light inner top
     highlight to suggest depth without leaning on gradients or glow. Flex
     (not a fixed-column grid) so however many tiles are present - five on a
     simple case load, more when every measurement type is in use - they
     always distribute evenly across each row; there's never an orphan
     single tile stranded alone on its own row. */
  .glance-grid{display:flex;flex-wrap:wrap;gap:10px;margin-top:10px}
  .glance-tile{flex:1 1 128px;background:linear-gradient(180deg,rgba(255,255,255,.95),rgba(244,248,247,.85));border:1px solid rgba(16,36,62,.08);border-radius:14px;padding:16px 12px;text-align:center;box-shadow:inset 0 1px 0 rgba(255,255,255,.8),0 1px 2px rgba(16,36,62,.05);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
  .glance-tile .g-num{font-size:26px;font-weight:700;line-height:1.15;color:var(--ink);letter-spacing:-.01em}
  .glance-tile .g-lbl{font-size:10.5px;color:var(--muted);margin-top:5px;font-weight:600;text-transform:uppercase;letter-spacing:.05em}
  .glance-tile .g-dot{display:inline-block;width:6px;height:6px;border-radius:50%;margin-right:5px;vertical-align:1px}
  .activity{max-width:660px;margin:0 auto 14px;background:var(--surface);border:1px solid var(--line);border-radius:16px;padding:16px 18px;box-shadow:0 2px 8px rgba(16,36,62,.07)}
  .activity-list{margin-top:6px;max-height:280px;overflow-y:auto}
  .activity-row{display:flex;align-items:flex-start;gap:10px;padding:7px 2px;border-bottom:1px solid #eef2f7}
  .activity-row:last-child{border-bottom:none}
  .a-dot{width:9px;height:9px;border-radius:50%;margin-top:5px;flex-shrink:0}
  .a-body{flex:1;min-width:0}
  .a-top{display:flex;justify-content:space-between;gap:8px;font-size:13px}
  .a-name{font-weight:700}
  .a-time{color:var(--muted);font-size:11.5px;white-space:nowrap}
  .a-action{font-size:12.5px;color:var(--muted);margin-top:1px}
  /* Now a real <button> on every event, not a <span> on one. It needs the
     button reset (admin-style default backgrounds do not apply here, but
     the browser's do) and a 24px hit area — it sits in a dense list that is
     tapped one-handed beside a student.
     v249 Workstream 29 (iPad/Mobile Pass). Was a hardcoded min-height:28px.
     A scoping audit flagged this control as under-target and suggested
     raising it to the full --target-touch (44px) - that would fight this
     comment's own documented intent (a deliberately dense control for a
     tight, one-handed timeline list), so instead tokenized to
     --target-dense (32px, foundations.css:66) - the same WCAG-2.2 24px-
     floor tier .link-btn already uses for the identical reason, closing
     the real gap (28px was already under even the dense tier) without
     abandoning the documented design choice to keep this control small. */
  .a-undo{font-size:11.5px;color:var(--brand);font-weight:700;cursor:pointer;
    white-space:nowrap;margin-top:4px;display:inline-flex;align-items:center;gap:4px;
    background:transparent;border:1px solid transparent;border-radius:999px;
    padding:4px 9px;min-height:var(--target-dense);font-family:inherit;margin-left:-9px}
  .a-undo:hover:not(:disabled){background:#eef4fb;border-color:#d5e3f2;color:var(--brand)}
  .a-undo:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
  .timeline{max-width:660px;margin:0 auto 14px;background:var(--surface);border:1px solid var(--line);border-radius:16px;padding:16px 18px;box-shadow:0 2px 8px rgba(16,36,62,.07);overflow-x:auto}
  .tl-row{display:flex;align-items:center;gap:10px;margin-top:8px}
  .tl-label{width:92px;flex-shrink:0;font-size:11.5px;font-weight:700;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .tl-track{flex:1;min-width:260px}
  .dash-row{display:block}

  /* ---- Desktop: the timeline becomes the primary live visualization
     directly under the board, and Live Activity + Session at a Glance sit
     side by side below it - all sharing the same width as the card row
     (.wrap's own max-width) instead of being squeezed into a narrow center
     column. Tablets (including iPad landscape, ~1024px) stay single-column
     so the recorder is still comfortable to use one-handed. ---- */
  @media(min-width:1180px){
    #session-bar{max-width:none}
    .timeline{max-width:none}
    .timeline .tl-track{min-width:0}
    .dash-row{display:flex;align-items:stretch;gap:16px;margin-bottom:14px}
    .dash-row .activity{flex:1 1 62%;max-width:none;margin:0}
    .dash-row .glance{flex:1 1 36%;max-width:none;margin:0;display:flex;flex-direction:column}
    .dash-row .glance-grid{flex:1}
    .activity-list{max-height:420px}
  }

  /* ---- Home / welcome screen: a calm landing point between login and the
     operational Active Session workspace ("what do I need to do?" rather
     than a dashboard of everything). ---- */
  .home-hero{max-width:660px;margin:4px auto 18px;display:flex;align-items:center;gap:16px}
  .home-hero img{height:72px;width:auto;object-fit:contain;flex-shrink:0;filter:drop-shadow(0 3px 6px rgba(16,36,62,.18))}
  .home-hero h1{font-size:21px;margin:0 0 3px;font-weight:700;color:var(--ink)}
  .home-hero p{margin:0;color:var(--muted);font-size:14px}
  .home-card{max-width:660px;margin:0 auto 14px;background:var(--surface);border:1px solid var(--line);border-radius:16px;padding:20px;box-shadow:0 2px 8px rgba(16,36,62,.07)}
  .home-active{background:linear-gradient(135deg,#10243E,#123D73);color:#fff;border:none;box-shadow:0 8px 22px rgba(16,36,62,.22)}
  .home-active .title{color:#9fb3c8}
  .home-attention{border-color:#f1c7c3;background:linear-gradient(180deg,#fff,#fff9f8)}
  .home-attention .title{color:var(--red)}
  .attention-count{min-width:24px;height:24px;padding:0 7px;border-radius:999px;background:var(--red);color:#fff;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:800}
  .attention-row{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:12px 0;border-bottom:1px solid #f4deda}
  .attention-row:last-child{border-bottom:none;padding-bottom:0}
  .attention-copy{min-width:0}
  .attention-title{font-size:13.5px;font-weight:750;color:var(--ink)}
  .attention-meta{font-size:12px;color:var(--muted);margin-top:2px;line-height:1.4}
  .attention-action{border:1px solid #d6e0e8;background:#fff;color:var(--brand);border-radius:9px;padding:8px 11px;font:700 12px inherit;cursor:pointer;white-space:nowrap}
  .attention-action.danger{border-color:#efc2bd;color:var(--red)}
  /* v249 (Workstream 16). The one attention row that genuinely has no
     action for this account to take (a flag awaiting a supervisor's
     reply) - plain text, no border/background/button chrome, so it
     never reads as a control that silently does nothing. */
  .attention-status{font-size:12px;font-weight:600;white-space:nowrap}
  .home-primary-btn{background:var(--brand);color:#fff;border:none;border-radius:12px;padding:13px 22px;font-size:15px;font-weight:700;cursor:pointer;font-family:inherit;box-shadow:0 3px 10px rgba(18,61,115,.25);white-space:nowrap}
  .home-start-row{display:flex;gap:10px;margin-top:2px;flex-wrap:wrap}
  .home-start-row select{flex:1 1 180px;padding:12px 14px;border:1px solid var(--line);border-radius:10px;font-family:inherit;font-size:14px}
  .home-recent-row{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid #eef2f7;font-size:13.5px}
  .home-recent-row:last-child{border-bottom:none}
  .home-recent-code{font-weight:700}
  .home-recent-meta{color:var(--muted);font-size:12px;margin-top:1px}
  .home-status-pill{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;padding:4px 9px;border-radius:999px;background:var(--green-bg);color:var(--green);white-space:nowrap}
  .home-status-pill.warn{background:var(--red-bg);color:var(--red)}
  .home-status-pill.muted{background:var(--slate-bg);color:var(--muted)}
  .link-btn{color:var(--brand);font-weight:700;font-size:13px;cursor:pointer;white-space:nowrap;background:none;border:none;font-family:inherit;padding:0}
  .correction-banner{max-width:1100px;margin:0 auto 12px;border:1px solid #e9b9b3;border-left:5px solid var(--red);border-radius:12px;background:#fff7f6;padding:13px 15px;color:var(--ink);font-size:13px;line-height:1.45;box-shadow:0 2px 8px rgba(121,31,23,.06)}
  .correction-banner strong{display:block;color:var(--red);font-size:13.5px;margin-bottom:2px}
  /* Organization announcements, posted from the admin console - a slim,
     continuously-scrolling ticker directly under the nav (Home only), in
     keeping with Home being a calm landing point rather than a dashboard. */
  .home-ticker{overflow:hidden;white-space:nowrap;background:linear-gradient(180deg,#fbfcfe,#f4f8f7);border-bottom:1px solid var(--line);box-shadow:inset 0 -1px 0 rgba(16,36,62,.03)}
  .home-ticker-track{display:inline-block;padding:9px 0;animation:home-tick 30s linear infinite}
  .home-ticker-item{display:inline-block;padding:0 30px;font-size:13px;color:var(--ink)}
  .home-ticker-dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--brand);margin-right:8px;vertical-align:1px}
  .home-ticker-item.alert{color:var(--red);font-weight:600}
  .home-ticker-item.alert .home-ticker-dot{background:var(--red)}
  /* Printing a Session Export: everything else on the page is hidden and
     only #print-area is shown, laid out for a clean printed/PDF page rather
     than the on-screen modal chrome (buttons, overlay, etc). The export
     itself is now a full multi-section document (Overview, Statistics,
     Graphs, Goals, Interventions, ABC, Notes, raw data) so it legitimately
     runs to several pages for a data-rich session - what this stylesheet
     guards against is UNNECESSARY pages: charts still run two-up instead of
     stacked full-width, fonts/padding are sized down from their on-screen
     equivalent, and each section avoids splitting its heading from its
     content across a page break.
     Note: #login/#app are hidden with display:none (not just
     visibility:hidden), which fully removes them - and everything nested in
     them - from the page layout. Just making them invisible still left
     their full height in the document flow, and the whole single-page app
     (every view/modal, even ones not showing) is tall enough on its own to
     force several extra blank printed pages - that was the real cause of
     early "it prints 4-5 blank-ish pages" reports, not the chart sizing.
     #print-area is kept as its own top-level element (a direct sibling of
     #app, right before </body>) precisely so hiding #app can never hide it
     too. */
  #print-area{ display:none; }
  @media print {
    /* V250 Workstream I. Identical to admin.css's block, for the same
       reason: a printed session recap is a clinical record and its
       continuation pages carried no identifier and no page number. The
       custom properties are set immediately before window.print(); the
       empty-string fallbacks mean a browser that ignores margin boxes
       prints exactly what it printed before. */
    @page{ margin:0.45in;
      @top-left{ content: var(--print-head, ""); font-size:8.5px; color:var(--muted); }
      @bottom-left{ content: var(--print-foot, ""); font-size:8.5px; color:var(--muted); }
      @bottom-right{ content: "Page " counter(page) " of " counter(pages); font-size:8.5px; color:var(--muted); }
    }
    #login, #app{ display:none !important; }
    #print-area{ display:block; width:100%; padding:0; font-family:inherit; color:var(--ink); font-size:12px; line-height:1.35; }
    #print-area h1{ font-size:16px; margin:0 0 1px; }
    #print-area h2{ font-size:11.5px; font-weight:600; color:var(--muted); margin:0 0 8px; }
    #print-area table{ width:100%; border-collapse:collapse; font-size:11px; margin-bottom:8px !important; }
    #print-area td, #print-area th{ padding:3px 4px; }
    /* Deliberately NOT page-break-inside:avoid on .review-section itself -
       a section like Statistics or the raw-data table can easily be taller
       than one page, and "avoid" on something that tall just pushes it
       whole onto the next page, leaving the rest of the current page
       blank (the same "invisible-but-still-tall" kind of bug as before).
       "avoid" only goes on the small, genuinely one-piece units nested
       inside a section: each target's own stat card below, and each
       chart-block above. */
    #print-area .review-section{ margin-bottom:10px !important; }
    #print-area .review-section .title{ font-size:12.5px !important; margin-bottom:4px; }
    #print-area .card{ page-break-inside:avoid; margin-top:6px !important; padding:8px 10px !important; font-size:11.5px !important; }
    #print-area img.sm-sig, #print-area img[alt="Signature"]{ max-width:130px !important; margin-bottom:8px; }
    #print-area .chart-grid{ display:flex; flex-wrap:wrap; gap:2px 18px; }
    #print-area .chart-block{ flex:1 1 46%; max-width:47%; margin-bottom:4px !important; page-break-inside:avoid; }
    #print-area .chart-block > div:first-child{ font-size:10px !important; }
    #print-area .chart-block svg text{ font-size:8px !important; }
  }
  @keyframes home-tick{from{transform:translateX(100%)}to{transform:translateX(-100%)}}

  /* ---- Session Review: a deliberate end-of-session workflow, not another
     long stack of equal-weight cards - a header establishes context, a
     status banner marks the shift out of live collection, sections are
     ordered by how much attention they need, and the signature/final-submit
     step is visually its own thing at the very end. ---- */
  .review-header{max-width:660px;margin:0 auto 4px}
  .review-header .rh-top{display:flex;align-items:center;gap:10px;margin-bottom:12px}
  .review-title{font-size:21px;font-weight:700;color:var(--ink)}
  .review-meta{color:var(--muted);font-size:13.5px;margin-top:3px;line-height:1.5}
  .review-status-banner{max-width:660px;margin:14px auto 18px;background:#eef2ff;border:1px solid #c7d2fe;color:var(--brand);border-radius:12px;padding:13px 16px;font-size:13.5px;display:flex;align-items:center;gap:10px}
  .review-section{max-width:660px;margin:0 auto 14px}
  .summary-toggle{display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:pointer}
  .summary-toggle .st-num{font-size:13px;color:var(--muted);margin-top:2px}
  .summary-toggle .st-link{color:var(--brand);font-weight:700;font-size:13px;white-space:nowrap;flex-shrink:0}
  .dq-row{display:flex;align-items:flex-start;gap:8px;padding:5px 0;font-size:13.5px}
  .dq-row.dq-ok{color:var(--green);font-weight:600}
  .dq-row.dq-warn{color:#92400e}
  .dq-row.dq-err{color:var(--red);font-weight:600}
  .sig-step-badge{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background:var(--brand);color:#fff;font-size:12px;font-weight:700;margin-right:8px;flex-shrink:0;vertical-align:-5px}
  .final-actions{max-width:660px;margin:20px auto 0;display:flex;gap:10px}
  .final-actions .cancel-btn{flex:1;border:1px solid var(--line);background:#fff;color:var(--muted);border-radius:12px;padding:14px;font-weight:700;font-size:14.5px;cursor:pointer;font-family:inherit}
  .final-actions .submit-btn{flex:2;border:none;background:var(--brand);color:#fff;border-radius:12px;padding:14px;font-weight:700;font-size:14.5px;cursor:pointer;font-family:inherit;box-shadow:0 3px 10px rgba(18,61,115,.25)}
  .final-actions .submit-btn:disabled{background:#cbd5e1;box-shadow:none;cursor:not-allowed;color:#94a3b8}
  .completion-panel{max-width:440px;margin:60px auto;text-align:center;background:var(--surface);border:1px solid var(--line);border-radius:20px;padding:40px 28px;box-shadow:0 8px 30px rgba(16,36,62,.1)}
  .completion-check{width:56px;height:56px;border-radius:50%;background:var(--green-bg);color:var(--green);display:flex;align-items:center;justify-content:center;font-size:26px;font-weight:700;margin:0 auto 18px}


/* v95 — keep live collection controls inside their cards */
#cards .card{min-width:0;overflow:hidden}
.btn-row{min-width:0;max-width:100%}
.btn-row>*{min-width:0;max-width:100%;box-sizing:border-box}
/* v203. The step row used to be hard-coded to three columns, which is what
   made three response levels feel like a law. It now sizes to however many
   levels the target configures: they fit on one row while they can, and wrap
   onto a second rather than shrinking below a tappable width. A clinically
   real response is never hidden to keep the row tidy. */
.step-row .btn-row,.lvl-row{display:grid;gap:6px;width:100%;
  grid-template-columns:repeat(auto-fit,minmax(52px,1fr))}
/* Up to four still get equal columns, which reads calmer than auto-fit's
   last-row stretch for the common cases. */
.lvl-row[style*="--lvl-n:2"]{grid-template-columns:repeat(2,minmax(0,1fr))}
.lvl-row[style*="--lvl-n:3"]{grid-template-columns:repeat(3,minmax(0,1fr))}
.lvl-row[style*="--lvl-n:4"]{grid-template-columns:repeat(4,minmax(0,1fr))}
.ta-lvl,.lvl-btn{min-width:0;padding-left:2px;padding-right:2px;
  font-variant-numeric:tabular-nums;letter-spacing:.01em}
/* v218. The trial buttons carry the code AND its meaning, because the codes
   are not standard - no source in the local library establishes IND/GP/VP/M,
   and a reviewing BCBA read them as ambiguous. The row needs wider columns to
   fit a name, so a long hierarchy wraps onto a second line rather than
   shrinking the buttons below a tappable width - the same rule the row above
   already follows: a clinically real response is never hidden to keep the row
   tidy. */
.trial-lvl-row{grid-template-columns:repeat(auto-fit,minmax(76px,1fr))}
.lvl-btn{flex-direction:column;gap:1px;min-height:44px;padding-top:6px;padding-bottom:6px;
  line-height:1.15;text-align:center}
.lvl-btn .lvl-code{font-size:14.5px;font-weight:700}
.lvl-btn .lvl-name{font-size:11px;font-weight:400;opacity:.72;overflow-wrap:anywhere}
/* The task-analysis card says once what the codes mean instead of repeating a
   name under every step button - seven levels across a dozen steps would push
   the steps themselves off the screen. */
.ta-key{display:flex;flex-wrap:wrap;gap:4px 12px;justify-content:center;
  margin-top:6px;color:var(--muted);font-size:11px;line-height:1.4}
.ta-key-item b{color:var(--ink);font-weight:700}
/* Selected state is fill and ink only - no corner accents, no edge slivers. */
.ta-lvl.is-scored{background:var(--brand);color:#fff;border-color:var(--brand);font-weight:700}
.ta-lvl:hover:not(:disabled),.lvl-btn:hover:not(:disabled){background:var(--slate-bg)}
.ta-lvl.is-scored:hover:not(:disabled){background:var(--brand2)}
.step-row .btn-row .small{
  width:100%;
  min-width:0;
  padding:7px 5px;
  font-size:12px;
  white-space:normal;
}
@media(max-width:520px){
  .btn-row{gap:5px}
  .big{font-size:13px;padding:8px 6px}
  .small{font-size:12px;padding:7px 8px}
  .step-row .btn-row .small{font-size:11.5px;padding:7px 4px}
}

/* v109 — Phase 3 Active Session Workspace navigation. Workspaces filter the
   live control surface only; they never duplicate targets or stop tools. */
.session-workspace-nav{margin:12px 0 14px;background:rgba(255,255,255,.96);border:1px solid var(--line);border-radius:16px;padding:13px 14px;box-shadow:0 3px 12px rgba(16,36,62,.07)}
.session-workspace-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
.session-workspace-kicker{font-size:9.5px;text-transform:uppercase;letter-spacing:.075em;font-weight:800;color:var(--muted)}
.session-workspace-current{font-size:16px;font-weight:700;color:var(--ink);margin-top:1px}
.session-workspace-actions{display:flex;gap:7px}
.session-workspace-step{border:1px solid var(--line);background:#fff;color:var(--brand);border-radius:10px;padding:7px 10px;font:600 12px inherit;cursor:pointer;white-space:nowrap}
.session-workspace-chips{display:flex;gap:7px;overflow-x:auto;padding:10px 1px 4px;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.session-workspace-chips::-webkit-scrollbar{display:none}
.session-workspace-chip{flex:0 0 auto;border:1px solid #dce5ec;background:#f8fafc;color:#536779;border-radius:999px;padding:8px 11px;font:600 12px inherit;cursor:pointer;transition:.12s}
.session-workspace-chip:hover{border-color:#b9cad8;background:#fff}
.session-workspace-chip.active{background:var(--brand);border-color:var(--brand);color:#fff;box-shadow:0 2px 7px rgba(18,61,115,.2)}
.session-workspace-meta{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-top:7px;padding-top:8px;border-top:1px solid #edf2f6;color:var(--muted);font-size:10.5px;line-height:1.45}
/* v235. .session-running-tools removed: the strip pushed the cards down whenever a timer started (owner, 2026-09-08). */
.workspace-empty{border:1px dashed #cbd8e2;background:#f8fbfd;border-radius:15px;padding:22px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:7px;color:var(--muted)}
.workspace-empty b{color:var(--ink);font-size:14px}
.workspace-empty span{max-width:580px;font-size:12px;line-height:1.5}
.workspace-empty button{margin-top:4px;border:0;background:var(--brand);color:#fff;border-radius:10px;padding:9px 13px;font:700 12px inherit;cursor:pointer}
@media(max-width:700px){
  .session-workspace-head{align-items:flex-start;flex-direction:column}
  .session-workspace-actions{width:100%}
  .session-workspace-step{flex:1}
  .session-workspace-meta{display:block}
  .session-workspace-meta span{display:block;margin-top:3px}
}

/* v110 — Workspace History (routine/context only; never a clinical score) */
.workspace-history-list{display:flex;flex-direction:column;gap:7px;margin-top:12px}
.workspace-history-row{display:grid;grid-template-columns:78px 64px minmax(0,1fr) auto;gap:8px;align-items:center;padding:9px 10px;border:1px solid var(--line);border-radius:10px;background:#fff;font-size:12.5px}
.workspace-history-time{font-variant-numeric:tabular-nums;color:var(--muted);font-weight:600}
.workspace-history-type{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:#46627d;font-weight:800}
.workspace-history-text{min-width:0;color:#18344f;font-weight:600}
.workspace-history-sync{font-size:10px;color:#8a6b16;background:#fff8db;border:1px solid #f1dfa0;border-radius:999px;padding:3px 7px;white-space:nowrap}
.workspace-history-foot,.workspace-history-empty{font-size:11.5px;color:var(--muted);padding:3px 2px}
.workspace-history-warning{font-size:11.5px;color:#9f2f24;background:#fff3f1;border:1px solid #f1c7c1;border-radius:9px;padding:8px 9px}
@media(max-width:700px){.workspace-history-row{grid-template-columns:68px 54px minmax(0,1fr)}.workspace-history-sync{grid-column:3;justify-self:start}}

/* v112 — Optional routine-time suggestions. Staff always choose whether to
   switch; the prompt never changes Workspace context automatically. */
.workspace-chip-clock{font-size:9px;margin-left:5px;opacity:.72}
.session-routine-suggestion{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:10px;align-items:center;margin-top:9px;padding:10px 11px;border-radius:11px;border:1px solid #cfe0ef;background:#f3f8fc;color:#24445f}
.session-routine-suggestion>i{font-size:17px;color:#376e9e}.session-routine-suggestion>span{display:flex;flex-direction:column;min-width:0}.session-routine-suggestion b{font-size:12px}.session-routine-suggestion small{font-size:10px;color:#71879a;margin-top:2px;line-height:1.35}.session-routine-suggestion>div{display:flex;gap:6px}.session-routine-suggestion button{border-radius:9px;padding:7px 9px;font:700 10.5px inherit;cursor:pointer;white-space:nowrap}.session-routine-suggestion .routine-switch{border:1px solid var(--brand);background:var(--brand);color:#fff}.session-routine-suggestion .routine-stay{border:1px solid #cbd9e4;background:#fff;color:#536b80}
@media(max-width:700px){.session-routine-suggestion{grid-template-columns:auto minmax(0,1fr)}.session-routine-suggestion>div{grid-column:1/-1}.session-routine-suggestion button{flex:1}}

/* v116 — Beta workflow hardening: if Workspace context cannot load, never
   silently hide collection controls. Fall back visibly to All Active Targets. */
.session-workspace-fallback{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:10px;align-items:center;color:#764a17}
.session-workspace-fallback>i{font-size:18px;color:#a36b18}.session-workspace-fallback>span{display:flex;flex-direction:column;min-width:0}.session-workspace-fallback b{font-size:12px;color:#624013}.session-workspace-fallback small{font-size:10px;line-height:1.4;color:#8a6a3f;margin-top:2px}.session-workspace-fallback button{border:1px solid #d8b77b;background:#fff;color:#795018;border-radius:9px;padding:7px 10px;font:700 10.5px inherit;cursor:pointer;white-space:nowrap}.session-workspace-fallback button:disabled{opacity:.6;cursor:wait}
@media(max-width:700px){.session-workspace-fallback{grid-template-columns:auto minmax(0,1fr)}.session-workspace-fallback button{grid-column:1/-1;width:100%}}

/* ============================================================
   v125 — Active Session UI QA round 2
   Keep the stacked sticky chrome and bottom action bar stable at laptop
   and phone widths. Layout-only; collection/session behavior is unchanged.
   ============================================================ */
html,body{max-width:100%;overflow-x:hidden}
.topbar{min-width:0;max-width:100%;height:56px;min-height:56px}
.topbar>*{min-width:0}
.topbar .spacer{flex:1 1 auto;min-width:0}
.topbar select{flex:0 1 260px;max-width:min(40vw,260px)}
.nav{top:56px;max-width:100%;overscroll-behavior-x:contain;scrollbar-width:thin;-webkit-overflow-scrolling:touch}
.wrap{width:100%;max-width:1100px;min-width:0}
.footer{max-width:100%;z-index:25}
.footer .wrapf{min-width:0}
.footer .attest{min-width:0}
.footer .status{min-width:0;overflow:hidden;text-overflow:ellipsis}
.feedback-modal{overscroll-behavior:contain}
.feedback-dialog{overscroll-behavior:contain}

@media(max-width:760px){
  .topbar{gap:8px;padding-left:10px;padding-right:10px}
  .topbar .clock{display:none}
  .topbar select{flex:1 1 180px;max-width:none}
  .footer .wrapf{gap:8px}
  .footer .status{white-space:normal;font-size:11px;line-height:1.25}
}
@media(max-width:600px){
  /* v235. The "not saved" indicator used to be hidden here, which left a
     phone with no way to see a refused write or open the recovery list. It
     stays, compact; the student select gives way instead. */
  .topbar .pending{font-size:12px;max-width:46vw;overflow:hidden;text-overflow:ellipsis}
  .topbar .offline{font-size:11px}
  .footer{padding:9px 10px}
  .footer .attest{display:none}
  .footer button{padding:11px 14px;font-size:13px}
}
@media(max-width:500px){
  .topbar{gap:6px;padding-left:8px;padding-right:8px}
  .topbar .brand .brand-icon{width:28px;height:28px}
  .topbar select{font-size:12px;padding:7px 8px}
  .topbar .feedback-open{display:none}
  /* Feedback goes on a phone; the way back to the console does not. A
     supervisor covering a classroom is the likeliest person to be on a phone
     and the likeliest to need the console, so this keeps its label and only
     gives up padding. */
  .topbar .admin-link{padding:7px 9px}
  .topbar .out{padding:7px 9px;font-size:12px}
  .nav{padding-left:8px;padding-right:8px}
  .navbtn{padding:8px 11px;font-size:12px}
  .wrap{padding-left:10px;padding-right:10px}
}
@media(max-width:420px){
  .topbar .brand{width:28px}
  .topbar select{min-width:0}
  /* v229. The footer status used to be display:none here, which on a phone
     removed the ONLY place a tap's result was written. It stays, one compact
     line above the button; important results also arrive as a toast. */
  .footer .wrapf{flex-wrap:wrap;gap:4px 8px}
  .footer .status{flex:1 1 100%;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:11.5px;line-height:1.3;text-align:center}
  .footer button{width:100%}
}

/* v166 — Paycom-like My Time / weekly timesheet */
.time-hero{padding:20px 22px}.time-hero-head,.time-period-head{display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.time-kicker{font-size:11px;font-weight:800;letter-spacing:.11em;color:#64748b}.time-state-pill,.time-period-status{display:inline-flex;align-items:center;border-radius:999px;padding:6px 10px;font-size:12px;font-weight:750;background:#f1f5f9;color:#475569;border:1px solid #e2e8f0}.time-state-pill.live{background:#ecfdf3;color:#166534;border-color:#bbf7d0}.time-period-status.submitted{background:#fff7ed;color:#9a3412;border-color:#fed7aa}.time-period-status.approved{background:#ecfdf3;color:#166534;border-color:#bbf7d0}.time-period-status.returned{background:#fff1f2;color:#9f1239;border-color:#fecdd3}.time-live{font-size:42px;line-height:1;font-weight:800;color:#10243e;margin-top:20px;letter-spacing:-.03em}.time-live-sub{font-size:12px;color:#64748b;margin-top:6px}.time-actions{display:flex;gap:10px;align-items:center;margin-top:18px}.time-punch-btn{border:0;border-radius:12px;background:#123d73;color:#fff;font-size:16px;font-weight:800;padding:13px 24px;min-width:150px;cursor:pointer}.time-punch-btn:hover{background:#0e315d}.time-punch-btn.out{background:#ff7a22}.time-punch-btn.out:hover{background:#e86817}.time-punch-btn:disabled{opacity:.55;cursor:wait}.time-context-grid,.time-week-summary{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:18px}.time-context-grid>div,.time-week-summary>div{background:#f8fafc;border:1px solid #e5edf3;border-radius:12px;padding:11px 12px}.time-context-grid span,.time-week-summary span{display:block;color:#64748b;font-size:11px;font-weight:700;margin-bottom:4px}.time-context-grid b,.time-week-summary b{font-size:14px;color:#10243e}.time-period-actions{display:flex;align-items:center;gap:8px}.time-week-table-wrap{overflow-x:auto;margin-top:14px}.time-week-table{min-width:680px}.time-week-table th{white-space:nowrap}.time-day-status{display:inline-flex;padding:4px 8px;border-radius:999px;font-size:11px;font-weight:750;background:#f1f5f9;color:#64748b}.time-day-status.ok{background:#ecfdf3;color:#166534}.time-day-status.live{background:#eaf3ff;color:#123d73}.time-day-status.warn{background:#fff7ed;color:#9a3412}.time-day-status.manual{background:#f5f3ff;color:#6d28d9}.time-manual-tag{display:inline-flex;align-items:center;border-radius:999px;padding:2px 6px;font-size:10px;font-weight:800;background:#f5f3ff;color:#6d28d9;margin-left:4px}.time-week-summary{grid-template-columns:repeat(4,minmax(0,1fr));margin-top:12px}.time-return-note{margin-top:12px;border:1px solid #fecdd3;background:#fff1f2;color:#9f1239;border-radius:10px;padding:10px 12px;font-size:12px;font-weight:650}.time-entry-row{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:11px 0;border-bottom:1px solid #eef2f7}.time-entry-row:last-child{border-bottom:0}.time-entry-side{display:flex;align-items:center;gap:8px;flex-wrap:wrap;justify-content:flex-end}.missing-punch-dialog{position:relative;background:#fff;width:min(520px,100%);border-radius:18px;box-shadow:0 24px 70px rgba(15,36,62,.25);padding:20px}.missing-punch-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}.missing-punch-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:14px}.missing-punch-grid label{display:flex;flex-direction:column;gap:6px;font-size:12px;font-weight:700;color:#334155}.missing-punch-grid .wide{grid-column:1/-1}.missing-punch-grid input,.missing-punch-grid textarea{width:100%;box-sizing:border-box}.missing-punch-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}
@media(max-width:720px){.time-context-grid,.time-week-summary{grid-template-columns:1fr 1fr}.time-hero-head,.time-period-head{align-items:stretch;flex-direction:column}.time-period-actions{justify-content:space-between}.time-punch-btn{flex:1}.time-actions{align-items:stretch}.missing-punch-grid{grid-template-columns:1fr}.missing-punch-grid .wide{grid-column:auto}.time-entry-row{align-items:flex-start}.time-live{font-size:36px}}

/* ═══ Recorder accessibility layer ════════════════════════════════════════
 * These three rules used to live in surfaces.css, which the Recorder loaded
 * AFTER collect.css. That put the ADMIN surface layer in a position to
 * override the Recorder's own stylesheet — every admin rule not scoped to a
 * #tab- container could reach this page. The Recorder had the coherent
 * layout of the two surfaces; letting the other one override it was
 * backwards. surfaces.css is no longer loaded here at all, and the rules
 * that genuinely belong to the Recorder live here, in load order.
 *
 * The base font-size bump on #view-* was dropped with the move. collect.css
 * never set a body font-size, so the base was already the browser's 16px and
 * the rule changed nothing it was supposed to change — it only added another
 * way for the layout to shift.
 * ═════════════════════════════════════════════════════════════════════════ */

/* Inline "→" links were 15px tall: real controls sized like text, well under
   WCAG 2.2's 24px floor, on a surface used one-handed beside a student. */
.link-btn{min-height:var(--target-dense);display:inline-flex;align-items:center;gap:var(--s-1);
  padding:0 var(--s-2);margin-left:calc(var(--s-2) * -1);border-radius:var(--r-sm);
  font-size:var(--fs-footnote);font-weight:var(--fw-semi);color:var(--accent-primary);
  background:transparent;border:0;cursor:pointer;
  transition:background var(--dur-quick) var(--ease-snappy)}
.link-btn:hover:not(:disabled){background:var(--accent-soft)}

/* Every recording control answers the press. On a touch surface this is the
   difference between "did that register?" and knowing it did. */
.collect-btn,.big-btn,.submitbtn,.out,.feedback-open{
  transition:transform var(--dur-instant) var(--ease-snappy),
             background var(--dur-quick) var(--ease-snappy)}
.collect-btn:active,.big-btn:active,.submitbtn:active{transform:scale(var(--lift-press))}
/* v223. The rate card's "events · tap to set" caption. Deliberately NOT
   `.sub`: on a rate card the first .sub is the rate line, which the glance
   code and the v202 observation harness read by that class. */
.count-caption{text-align:center;color:var(--muted);font-size:12px;line-height:1.3}

/* v225 (E12) — the latency card's "No response" control. Disabled until the
   plan sets a response window; once the window has elapsed it is the
   suggested tap. Fill and ink only. */
.lat-nr{background:#f1f3f6;color:#10243e;border:1px solid var(--line)}
.lat-nr:disabled{opacity:.55;cursor:not-allowed}
.lat-nr.is-due:not(:disabled){background:#fff2d6;color:#7a4b0b;border-color:#efd9a8;font-weight:700}
.lat-nr.is-due:not(:disabled):hover{background:#ffe6b8}

/* ═══ v229 — Recorder remediation ══════════════════════════════════════════
 * Session actions row, plan-state banner, one Note sheet, notes in Review,
 * interval "Start observation" state, and touch targets. Fill and ink carry
 * every state here - no edge slivers, per the owner's rule. */

/* Session actions sit as a strip attached under the session bar: the plan
   button (existing) and the Note button (new) share one row. */
.session-actions{display:flex;gap:1px;background:#0e2f57;border-radius:0 0 12px 12px;overflow:hidden}
#session-toolbar:has(#session-actions:not(.hidden)) #session-bar{border-radius:12px 12px 0 0;margin-bottom:0}
#session-toolbar:has(#session-actions:not(.hidden)) #plan-btn{border-radius:0;flex:1 1 auto;width:auto}
#session-toolbar:has(#session-actions:not(.hidden)) #plan-btn.hidden{display:none}
#note-btn{flex:0 0 auto;background:#0e2f57;color:#fff;border:none;border-top:1px solid rgba(255,255,255,.14);padding:7px 18px;min-height:44px;font-weight:700;font-size:13px;cursor:pointer;font-family:inherit}
#note-btn:hover:not(:disabled){background:#123D73}
#note-btn:focus-visible{outline:2px solid #fff;outline-offset:-3px}
#session-toolbar:has(#plan-btn.hidden) #note-btn{flex:1 1 auto;text-align:left;padding-left:16px}

/* Session bar additions: the idle dot while the session has no row yet, and
   the timer / note counts. */
#session-bar .live-dot.is-idle{background:#c3d2e2;box-shadow:none;animation:none}
#session-bar .sb-timers b,#session-bar .sb-notes b{color:#fff}
#session-bar .sb-timers{color:#ffe6b8}

/* Plan-state banner. Amber for "draft only" (a warning that needs the BCBA),
   slate for "no plan" (a clear state, not an error). Uniform border: the
   left-edge sliver the correction banner used is exactly the pattern the
   design rule forbids, so both banners now carry state in fill and ink. */
.correction-banner{border-left-width:1px}
.plan-banner.is-draft{border-color:#efd9a8;background:#fff8e8;box-shadow:0 2px 8px rgba(122,75,11,.06)}
.plan-banner.is-draft strong{color:#7a4b0b}
.plan-banner.is-none{border-color:var(--line);background:#f5f7fa;box-shadow:none}
.plan-banner.is-none strong{color:#334155}
.plan-banner ul{margin:6px 0 0;padding-left:18px}
.plan-banner li{margin:2px 0}

/* Per-card Note link in the head-actions row. */
.card .head-actions{gap:8px;align-items:center}
.card-note-link{background:transparent;border:1px solid var(--line);color:var(--brand);border-radius:999px;padding:0 14px;min-height:44px;font-size:12.5px;font-weight:700;font-family:inherit;cursor:pointer;display:inline-flex;align-items:center;gap:4px}
.card-note-link:hover:not(:disabled){background:#eef2ff}
.card-note-link:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
/* V251 R1. A target that already carries a note. Carried by FILL, INK and
   WEIGHT - a filled pill in the same brand family, not a sliver, bracket or
   edge marker clinging to the card (see CLAUDE.md). The hover rule repeats
   :not(:disabled) and declares background explicitly so it ties rather than
   loses to any button:hover catch-all. */
.card-note-link.has-notes{background:#EEF2FF;border-color:var(--brand);color:var(--brand)}
.card-note-link.has-notes:hover:not(:disabled){background:#DEE6FB}

/* The Note sheet: a bottom sheet on a phone, a centred dialog on a tablet. */
.note-sheet{background:#fff;width:100%;max-width:560px;max-height:min(92vh,92dvh);overflow:auto;border-radius:18px 18px 0 0;padding:18px 18px calc(18px + env(safe-area-inset-bottom,0px));box-shadow:0 -12px 40px rgba(15,23,42,.28);overscroll-behavior:contain}
@media(min-width:700px){#note-modal{align-items:center;padding:20px}.note-sheet{border-radius:16px;padding:22px 24px}}
.note-sheet-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}
.note-sheet-head .small{min-width:44px;min-height:44px;padding:0}
.note-field{display:block;font-size:12.5px;font-weight:700;color:#334155;margin-top:12px}
.note-field select,.note-field textarea{display:block;width:100%;margin-top:6px;font-weight:400;color:var(--ink);font-size:15px}
.note-field select{border:1px solid var(--line);border-radius:12px;padding:11px 12px;min-height:44px;background:#fff;font-family:inherit}
.note-field textarea{min-height:110px}
.note-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
/* v249 Workstream 29 (iPad/Mobile Pass). Was min-height:40px, a real gap
   below --target-touch (app/foundations.css:65) with no documented
   reason to stay dense - unlike .a-undo below, nothing here says this
   chip is meant to be a small, tightly-packed control. */
.note-chip{border:1px solid var(--line);background:#fff;color:#334155;border-radius:999px;padding:0 14px;min-height:var(--target-touch);font-size:13px;font-weight:600;font-family:inherit;cursor:pointer}
.note-chip:hover:not(:disabled){background:#f1f5f9}
.note-chip[aria-pressed="true"]{background:var(--brand);border-color:var(--brand);color:#fff}
.note-chip:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.note-flag{margin-top:14px}
.note-flag input{width:22px;height:22px}
.note-sheet-actions{display:flex;gap:10px;margin-top:16px}
.note-sheet-actions .small{min-height:48px;padding:0 18px}
.note-sheet-actions .submitbtn{flex:1;min-height:48px}
#note-sheet-msg{margin-top:8px}
#note-sheet-msg.is-error{color:var(--red);font-weight:600}

/* Notes in Review. */
.notes-list{display:flex;flex-direction:column;gap:8px}
.note-row{background:#f8fafc;border:1px solid var(--line);border-radius:12px;padding:10px 12px}
.note-row.is-flagged{background:#fff8e8;border-color:#efd9a8}
.note-row-head{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;font-size:12px;color:var(--muted)}
.note-row-head .note-when{font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.note-row-head .note-target{font-weight:600;color:#334155}
.note-flag-badge{background:#7a4b0b;color:#fff;border-radius:999px;padding:2px 8px;font-size:10.5px;font-weight:700;letter-spacing:.02em}
.note-row-head .note-remove{margin-left:auto}
.note-text{margin-top:6px;font-size:14px;line-height:1.45;color:var(--ink);white-space:pre-wrap;overflow-wrap:anywhere}

/* Interval card before "Start observation": score buttons exist (so the
   layout does not jump) but are plainly inert. */
.btn-row.int-waiting .big:disabled{opacity:.45;cursor:not-allowed;filter:none}
.int-not-started{color:var(--muted)}

/* Rate cards are the only place a count is turned into a per-minute figure.
   Their +1 is tinted with the badge colour, so at a glance a frequency card
   (brand blue +1) and a rate card (violet +1) are not the same control. */
.card:has(.badge.rate) .big.primary[data-act="plus"]{background:#5b21b6;box-shadow:0 3px 10px rgba(91,33,182,.28)}

/* Touch targets: every scoring control meets 44px. The 40px .big and 38px
   .small were the v228 P2.
   v249 Workstream 29 (iPad/Mobile Pass). A scoping audit flagged .big/
   .small as still rendering at those original 40px/38px values below
   --target-touch (app/foundations.css:65) - disproven by reading the
   full cascade: this override, later in the same file at equal
   specificity, already wins and renders both at the real 44px. Tokenized
   the literal 44px to var(--target-touch) here so the two stay tied to
   the one sizing authority - no rendered-size change, just removes a
   second hardcoded copy of the same number. */
.big{min-height:var(--target-touch)}
.small{min-height:var(--target-touch)}
.lat-nr{min-height:var(--target-touch)}

/* Toasts must not land under the fixed footer. */
body:has(.footer:not(.hidden)) .bd-toasts{bottom:calc(var(--s-4) + 84px)}
@media(max-width:640px){body:has(.footer:not(.hidden)) .bd-toasts{bottom:calc(var(--s-3) + 96px)}}

/* ═══ v235 (P0-2) — latency card while the cue timer runs. The primary
   control keeps the full row; No response and Cancel share a second row.
   Long clinical labels wrap instead of overflowing. */
.lat-row.is-running{flex-wrap:wrap}
.lat-row.is-running>.big{flex:1 1 100%}
.lat-secondary{display:flex;gap:6px;width:100%;min-width:0}
.lat-secondary>button{flex:1 1 0;min-width:0;min-height:44px;white-space:normal;line-height:1.2;font-size:13.5px}
.big{white-space:normal;line-height:1.2;overflow-wrap:anywhere}
/* v235 — recovery list wording */
.fq-summary{font-size:13px;color:#10243e;line-height:1.4;margin-top:4px}
.fq-tech{margin-top:4px}.fq-tech summary{font-size:11.5px;color:var(--muted);cursor:pointer}.fq-tech pre{font-size:11px;white-space:pre-wrap;word-break:break-word;background:#f6f8fa;border:1px solid var(--line);border-radius:8px;padding:6px 8px;margin:4px 0 0}
.small.danger-lite{background:#fff5f4;color:#8d3d33;border:1px solid #efc9c3}
.small.danger-lite:hover:not(:disabled){background:#ffe9e6}

/* v235. The card's ••• and the entry sheet (add a previous event / correct an
   entry). Selected states are fill and ink only - no edge slivers. */
.card-more{background:transparent;border:1px solid var(--line);color:var(--muted);border-radius:999px;min-width:44px;min-height:44px;padding:0 10px;font-size:14px;font-weight:700;letter-spacing:1px;font-family:inherit;cursor:pointer;display:inline-flex;align-items:center;justify-content:center}
.card-more:hover:not(:disabled){background:#f1f5f9;color:var(--ink)}
.card-more:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.es-options{display:grid;gap:8px}
.es-option,.es-entry{display:block;width:100%;text-align:left;border:1px solid var(--line);border-radius:12px;padding:12px 14px;background:#fff;font-family:inherit;cursor:pointer;min-height:56px;color:var(--ink)}
.es-option b{display:block;font-size:14.5px;color:var(--ink)}
.es-option span,.es-entry span{display:block;font-size:12.5px;color:var(--muted);margin-top:2px;line-height:1.35}
.es-entry{min-height:52px;padding:10px 14px}
.es-entry b{font-size:13.5px;font-variant-numeric:tabular-nums}
.es-option:hover:not(:disabled),.es-entry:hover:not(:disabled){background:#f1f5f9}
.es-option:disabled{opacity:.55;cursor:default}
.es-option:focus-visible,.es-entry:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.es-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:8px}
.es-inline{font-size:13px;color:#334155;font-weight:600}
.es-num{width:110px;max-width:100%;border:1px solid var(--line);border-radius:12px;padding:10px 12px;min-height:44px;font-size:16px;font-family:inherit;color:var(--ink);background:#fff}
.es-num:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
.es-notice{background:#fff7ed;border:1px solid #fed7aa;border-radius:12px;padding:12px 14px;font-size:13.5px;line-height:1.45;color:#7c2d12}
.es-picked{background:#f8fafc;border:1px solid var(--line);border-radius:12px;padding:10px 12px;font-size:13.5px;color:var(--ink);line-height:1.4}
#es-msg.is-error{color:var(--red);font-weight:600}

/* v235 (owner). Timer start/stop must not move the page.
   - the session bar's timing chip is always present (invisible when idle)
   - the latency card's second zone holds the summary OR the running controls */
#session-bar .sb-timers.is-idle{visibility:hidden}
.lat-secondary.is-idle{align-items:center;justify-content:center;min-height:44px}
.lat-secondary.is-idle>.sub{margin:0;text-align:center;line-height:1.3}
.lat-row:not(.is-running){flex-wrap:wrap}
.lat-row:not(.is-running)>.big{flex:1 1 100%}
/* The latency primary reserves two text lines, so a long response label
   ("Begins moving toward the door with materials") does not make the card
   taller the moment the cue starts. */
.lat-row>.big{min-height:53px}
/* v242 — visual timer (Duration + Latency). A state ring, the elapsed time
   large, one line naming the state. The ring is a state treatment (empty =
   ready, full brand = timing, green = recorded, amber = window passed, dashed
   amber = no response) and fills as progress only when a real response window
   exists. Constant height, so a card never grows when a clock starts. */
.tmr{display:flex;align-items:center;gap:14px;min-height:88px;margin:2px 0 8px}
.tmr-ring{width:72px;height:72px;flex:0 0 72px;transform:rotate(-90deg)}
.tmr-track{fill:none;stroke:#e6ecf0;stroke-width:6}
.tmr-arc{fill:none;stroke:var(--brand);stroke-width:6;stroke-linecap:round;transition:stroke .2s ease,opacity .2s ease}
.tmr-arc--solid{stroke-dasharray:213.6;stroke-dashoffset:0}
.tmr-arc--progress{transition:stroke-dashoffset .25s linear,stroke .2s ease,opacity .2s ease}
.tmr--idle .tmr-arc{opacity:0}
.tmr--recorded .tmr-arc{stroke:var(--green);stroke-dashoffset:0}
.tmr--due .tmr-arc{stroke:var(--amber)}
.tmr--noresp .tmr-arc{stroke:var(--amber);stroke-dasharray:5 9;stroke-dashoffset:0}
.tmr-text{min-width:0;flex:1 1 auto}
.tmr-time{font-size:32px;font-weight:700;line-height:1;font-variant-numeric:tabular-nums;color:var(--ink);white-space:nowrap;margin:0;text-align:left}
.tmr--wide .tmr-time{font-size:26px}
.tmr--noresp .tmr-time{font-size:22px;color:#7a4b0b}
.tmr-state{font-size:12.5px;color:var(--muted);margin-top:5px;line-height:1.3}
.tmr--running .tmr-state{color:var(--brand);font-weight:600}
.tmr--due .tmr-state{color:#7a4b0b;font-weight:700}
.tmr--recorded .tmr-state{color:var(--green);font-weight:600}
.tmr--noresp .tmr-state{color:#7a4b0b;font-weight:600}
@media (prefers-reduced-motion:reduce){.tmr-arc,.tmr-arc--progress{transition:none}}
