/* TutorSeek — plain CSS, no framework, no CDN. Works offline.

   The palette is jade and amber: a fresh green that reads as "go ahead" and a
   warm amber that reads as "look here". It is deliberately brighter and
   warmer than the deep blue-green this app started with, because the thing
   being booked is an afternoon with a teacher and not an appointment at a
   bank.

   Every colour is a custom property, and every one of them is redefined by
   /api/theme.css from the three colours set in the console. This block is the
   starting point and the offline fallback; the console is the control.

   ---------------------------------------------------------------------------
   Day and night, in three states rather than two.

   :root                                  the day palette
   @media dark + :not([data-theme=light]) night, when the phone says night
   :root[data-theme="dark"]               night, because a person chose it

   Nothing stamped on <html> means "do what the operating system does". The
   guard on the middle block is what lets somebody choose day on a phone that
   is in night mode and actually get day — without it, the media query would
   win and the choice would do nothing.

   These selectors must stay identical to the ones theme_css() writes in
   server.py. Both files set the same properties, and a heavier selector in
   one would quietly beat the other regardless of load order. */

:root{
  --brand:#0B7459;          /* the bar, headings, the deepest ink */
  --brand-2:#0C8163;        /* primary buttons */
  --brand-3:#0C8163;        /* links, focus rings */
  --brand-4:#76C6B0;
  --accent:#FFB627;         /* rules, selections, anything that must be seen */
  --accent-deep:#8A6315;
  --accent-wash:#F6ECCD;
  --cool:#2F4A8C;
  --red:#B03427;
  --danger:#8A291F;
  --red-wash:#F5E1DC;
  --green:#0F7C54;
  --green-wash:#D5EEE2;
  --paper:#F4FAF6;
  --panel:#FEFFFE;
  --ink:#042E24;
  --muted:#5C746C;
  --line:#C6E7DD;
  --line-soft:#DDF0E9;

  /* Tinted with the brand rather than grey, and spread wider than before.
     A grey shadow under a warm card is what makes an interface look
     photocopied. */
  --shadow:0 1px 2px rgba(11,116,89,.06), 0 8px 24px rgba(11,116,89,.08);
  --shadow-lift:0 2px 8px rgba(11,116,89,.10), 0 18px 44px rgba(11,116,89,.16);

  /* One scale of corners, so a button, a card and a modal are visibly the
     same family rather than three people's guesses. Rounder than it was:
     the single cheapest way to make an interface look friendly. */
  --radius:12px;
  --radius-lg:18px;
  --radius-xl:28px;
  --radius-pill:999px;

  /* Motion, named once, so the reduced-motion block at the foot can flatten
     all of it in one place. */
  --ease:cubic-bezier(.22,.61,.36,1);
  --quick:.14s;
  --calm:.26s;

  --sans:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --mono:ui-monospace,"SFMono-Regular",Consolas,"Liberation Mono",Menlo,monospace;
}

@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --brand:#074636;
    --brand-2:#23846B;
    --brand-3:#87CDBB;
    --brand-4:#095D47;
    --accent:#FFC24A;
    --accent-deep:#FFB627;
    --accent-wash:#30280F;
    --cool:#8FB2EE;
    --red:#F08A7E;
    --danger:#912B20;
    --red-wash:#2B1714;
    --green:#57CB99;
    --green-wash:#0B271E;
    --paper:#142723;
    --panel:#263734;
    --ink:#F5FAF6;
    --muted:#A2ACA8;
    --line:#3C4C48;
    --line-soft:#334340;
    --shadow:0 1px 2px rgba(0,0,0,.40), 0 8px 24px rgba(0,0,0,.34);
    --shadow-lift:0 2px 8px rgba(0,0,0,.45), 0 18px 44px rgba(0,0,0,.50);
  }
}

:root[data-theme="dark"]{
  --brand:#074636;
  --brand-2:#23846B;
  --brand-3:#87CDBB;
  --brand-4:#095D47;
  --accent:#FFC24A;
  --accent-deep:#FFB627;
  --accent-wash:#30280F;
  --cool:#8FB2EE;
  --red:#F08A7E;
  --danger:#912B20;
  --red-wash:#2B1714;
  --green:#57CB99;
  --green-wash:#0B271E;
  --paper:#142723;
  --panel:#263734;
  --ink:#F5FAF6;
  --muted:#A2ACA8;
  --line:#3C4C48;
  --line-soft:#334340;
  --shadow:0 1px 2px rgba(0,0,0,.40), 0 8px 24px rgba(0,0,0,.34);
  --shadow-lift:0 2px 8px rgba(0,0,0,.45), 0 18px 44px rgba(0,0,0,.50);
}

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font:16px/1.55 var(--sans);
  -webkit-text-size-adjust:100%;
}
a{color:var(--brand-3)}
h1,h2,h3{line-height:1.25;margin:0 0 .4em}
h1{font-size:1.5rem;letter-spacing:-.01em}
h2{font-size:1.2rem}
h3{font-size:1rem}
p{margin:0 0 .8em}
.hide{display:none !important}
.muted{color:var(--muted)}
.small{font-size:.86rem}
.mono{font-family:var(--mono)}
.right{text-align:right}
.center{text-align:center}
.row{display:flex;gap:10px;align-items:center}
.row.wrap{flex-wrap:wrap}
.grow{flex:1 1 auto;min-width:0}
.stack{display:flex;flex-direction:column;gap:12px}
.spacer{height:12px}
.nowrap{white-space:nowrap}
.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ---------------------------------------------------------------- shell */

.app{display:flex;flex-direction:column;min-height:100%}

.topbar{
  position:sticky;top:0;z-index:30;
  display:flex;align-items:center;gap:12px;
  padding:10px 14px;
  background:var(--brand);
  color:#fff;
  box-shadow:var(--shadow);
  /* A hairline of accent under the bar. Cheap, and it stops the header from
     being a solid slab of one colour. */
  border-bottom:2px solid var(--accent);
}
.topbar .brand{display:flex;align-items:center;gap:10px;min-width:0}
.topbar .brand b{font-size:1.02rem;letter-spacing:.2px}
/* A long name will destroy a phone header unless it is told not to wrap —
   and that goes for the app's own name as much as the school's. Both lines
   are held to one line each and cut with an ellipsis instead. */
.topbar .brand{overflow:hidden}
.topbar .brand b{
  display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.topbar .brand span{
  display:block;
  color:rgba(255,255,255,.76);font-size:.82rem;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.topbar .crest{
  width:34px;height:34px;border-radius:var(--radius-pill);
  /* Fixed cream, not --accent-wash. The wash correctly turns dark at night,
     but this medallion sits on the bar, and the bar is dark in both themes
     because white text has to be readable on it. A wash that follows the
     theme puts a dark mark on a dark disc and the logo disappears. */
  background:#FFF6E3;color:var(--brand);
  display:grid;place-items:center;font-weight:700;flex:none;
  overflow:hidden;
}
.topbar .crest svg{width:24px;height:24px;display:block}
.topbar .grow{flex:1}
.chip-balance{
  background:rgba(255,255,255,.16);color:#fff;
  border-radius:var(--radius-pill);padding:5px 13px;
  font-variant-numeric:tabular-nums;font-size:.9rem;white-space:nowrap;
}

/* ------------------------------------------------------- day / night switch
   One button, three states, cycling system -> day -> night. The glyph is
   chosen by an attribute on <html> rather than by rewriting the button, so
   the control cannot get out of step with the theme it is reporting. */

.btn-theme{
  appearance:none;cursor:pointer;flex:none;
  width:38px;height:38px;padding:0;
  display:grid;place-items:center;
  border-radius:var(--radius-pill);
  border:1px solid rgba(255,255,255,.28);
  background:rgba(255,255,255,.10);color:#fff;
  transition:background var(--quick) var(--ease),transform var(--quick) var(--ease);
}
.btn-theme:hover{background:rgba(255,255,255,.20)}
.btn-theme:active{transform:scale(.94)}
.btn-theme:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.btn-theme svg{width:19px;height:19px;display:none;fill:currentColor}
:root:not([data-theme-choice]) .btn-theme .ic-system,
:root[data-theme-choice="system"] .btn-theme .ic-system,
:root[data-theme-choice="light"] .btn-theme .ic-day,
:root[data-theme-choice="dark"] .btn-theme .ic-night{display:block}

/* ------------------------------------------------------------- the bell

   A dropdown, not a page you have to go to. Anchored to the button rather
   than the bar so it stays put when the balance chip beside it changes
   width, and capped in height so forty notifications cannot push the close
   button off the bottom of a phone. */

.bell-wrap{position:relative;flex:none}
/* The bell borrows the switch's shape, and the switch hides every svg inside
   itself so it can show one glyph of three. Without this the bell button is
   an empty circle. */
.btn-theme.bell svg{display:block}
.bell-badge{
  position:absolute;top:-3px;right:-3px;
  min-width:19px;height:19px;padding:0 5px;
  border-radius:var(--radius-pill);
  background:var(--accent);color:#3A2A00;
  border:2px solid var(--brand);
  font-size:.68rem;font-weight:700;line-height:15px;text-align:center;
  font-variant-numeric:tabular-nums;
}
.bell[aria-expanded="true"]{background:rgba(255,255,255,.24)}

.menu{
  position:absolute;top:calc(100% + 10px);right:0;z-index:50;
  width:min(380px,calc(100vw - 24px));
  background:var(--panel);color:var(--ink);
  border:1px solid var(--line);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-lift);overflow:hidden;
  animation:drop var(--quick) var(--ease);
}
@keyframes drop{from{opacity:0;transform:translateY(-6px)}}
.menu-head{
  display:flex;align-items:center;gap:10px;
  padding:12px 14px;border-bottom:1px solid var(--line);
}
.menu-head b{flex:1;font-size:.95rem}
.menu-body{max-height:min(58vh,420px);overflow-y:auto}
.menu-foot{padding:8px 14px;border-top:1px solid var(--line);text-align:center}

.linky{
  appearance:none;border:0;background:none;cursor:pointer;
  font:inherit;font-size:.82rem;color:var(--brand-3);padding:4px 2px;
  border-radius:6px;
}
.linky:hover{text-decoration:underline}
.linky:focus-visible{outline:2px solid var(--brand-3);outline-offset:1px}

/* One row. The whole row is the button — a small "mark read" target beside a
   large "open it" target is a coin toss on a phone. */
.notif{
  display:flex;gap:11px;width:100%;text-align:left;
  padding:11px 14px;border:0;border-bottom:1px solid var(--line-soft);
  background:none;font:inherit;color:inherit;cursor:pointer;
}
.notif:last-child{border-bottom:0}
.notif:hover{background:var(--line-soft)}
.notif:focus-visible{outline:2px solid var(--brand-3);outline-offset:-2px}
.notif.unread{background:var(--accent-wash)}
.notif.unread:hover{filter:brightness(.98)}
.notif .ico{
  width:32px;height:32px;border-radius:var(--radius-pill);flex:none;
  display:grid;place-items:center;background:var(--line-soft);color:var(--brand-3);
}
.notif .ico svg{width:17px;height:17px;fill:currentColor;display:block}
.notif .ico.money{background:var(--green-wash);color:var(--green)}
.notif .ico.warn{background:var(--accent-wash);color:var(--accent-deep)}
.notif .ico.bad{background:var(--red-wash);color:var(--red)}
.notif .txt{min-width:0;flex:1}
.notif .txt b{display:block;font-size:.9rem;font-weight:600}
.notif .txt span{
  display:block;font-size:.82rem;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
}
.notif .txt time{display:block;font-size:.72rem;color:var(--muted);margin-top:3px}
.notif .fresh{
  width:8px;height:8px;border-radius:var(--radius-pill);
  background:var(--accent);flex:none;align-self:center;
}

/* The alerts page reuses the row, so it needs the card's edges round it. */
#alerts-list .notif{border-radius:0}
#alerts-list{
  background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow);
}

/* ------------------------------------------------------------- materials */

.mat{display:flex;gap:12px;align-items:flex-start}
.mat .ico{
  width:40px;height:40px;border-radius:var(--radius);flex:none;
  display:grid;place-items:center;
  background:var(--accent-wash);color:var(--accent-deep);
}
.mat .ico svg{width:20px;height:20px;fill:currentColor;display:block}
.mat.link .ico{background:var(--green-wash);color:var(--green)}
.mat .grow b{display:block}
.mat .meta{font-size:.8rem;color:var(--muted)}
.mat.gone{opacity:.55}

/* On a narrow phone the crest, the balance, the switch and Sign out between
   them leave the name about a hundred pixels. The crest is the least useful
   of them — the app is already the app — so it is the one that goes. */
@media (max-width:430px){
  .topbar{gap:8px;padding:8px 10px}
  .topbar .crest{display:none}
  .topbar .brand b{font-size:.96rem}
  #btn-signout{padding:6px 10px;font-size:.85rem;min-height:36px}
  .btn-theme{width:34px;height:34px}
  .menu{
    /* Anchored to the bar rather than the button, or a 380px panel hanging
       off a button near the right edge runs off the screen. */
    position:fixed;top:56px;left:8px;right:8px;width:auto;
  }
}

.tabs{
  display:flex;gap:2px;overflow-x:auto;
  background:var(--panel);border-bottom:1px solid var(--line);
  position:sticky;top:54px;z-index:20;
  scrollbar-width:none;
}
.tabs::-webkit-scrollbar{display:none}
.tabs button{
  appearance:none;border:0;background:none;cursor:pointer;
  padding:12px 14px;font:inherit;font-size:.94rem;color:var(--muted);
  border-bottom:3px solid transparent;white-space:nowrap;
  transition:color var(--quick) var(--ease);
}
.tabs button:hover{color:var(--brand-3)}
.tabs button.on{color:var(--brand-3);border-bottom-color:var(--accent);font-weight:600}
.tabs button .dot{
  display:inline-block;min-width:18px;padding:0 5px;margin-left:6px;
  background:var(--red);color:#fff;border-radius:var(--radius-pill);
  font-size:.72rem;line-height:18px;text-align:center;
}

#gatebar{
  background:var(--accent-wash);border-bottom:1px solid var(--accent);
  color:var(--ink);padding:12px 16px;font-size:.9rem;
}
#gatebar b{display:block;margin-bottom:2px}

main{flex:1;padding:16px;max-width:1100px;width:100%;margin:0 auto}
.page{display:none}
.page.on{display:block}

/* ---------------------------------------------------------------- cards */

.card{
  background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius-lg);padding:16px;box-shadow:var(--shadow);
}
.card + .card{margin-top:12px}
.card h3{margin-bottom:2px}
.card .head{display:flex;align-items:flex-start;gap:12px}
/* The price column sets its own width and never wraps. Left to fend for
   itself it gets squeezed to two characters a line by a long name beside it. */
.card .head > .right{flex:none;min-width:92px}
.card .head > .right > *{white-space:nowrap}
.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}
.stats{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}
.stat{
  background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius);padding:12px;
}
.stat b{display:block;font-size:1.4rem;font-variant-numeric:tabular-nums;
        color:var(--brand-3)}
.stat span{color:var(--muted);font-size:.82rem}
.stat.warn b{color:var(--red)}

.face{
  width:44px;height:44px;border-radius:var(--radius-pill);flex:none;
  overflow:hidden;background:var(--line-soft);display:grid;place-items:center;
}
.face img{width:100%;height:100%;object-fit:cover;display:block}
.face.big{width:88px;height:88px}
.face.small{width:30px;height:30px}

.pill{
  display:inline-block;padding:2px 10px;border-radius:var(--radius-pill);
  font-size:.78rem;font-weight:600;background:var(--line-soft);color:var(--muted);
}
.pill.ok{background:var(--green-wash);color:var(--green)}
.pill.warn{background:var(--accent-wash);color:var(--accent-deep)}
.pill.bad{background:var(--red-wash);color:var(--red)}
.pill.live{background:var(--green);color:#fff}

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

label{display:block;font-size:.85rem;color:var(--muted);margin:0 0 4px}
input,select,textarea{
  width:100%;padding:10px 12px;font:inherit;color:var(--ink);
  background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius);
}
textarea{min-height:100px;resize:vertical}
/* A colour input left to the default padding renders as a thin line nobody
   can hit. It gets the same height as everything else on the form. */
input[type=color]{height:46px;padding:4px;cursor:pointer}
input:focus,select:focus,textarea:focus{
  outline:2px solid var(--brand-3);outline-offset:1px;border-color:var(--brand-3);
}
.field{margin-bottom:12px}
.two{display:grid;gap:12px;grid-template-columns:1fr 1fr}
@media (max-width:560px){.two{grid-template-columns:1fr}}

button.btn{
  appearance:none;cursor:pointer;font:inherit;font-weight:600;
  padding:10px 16px;border-radius:var(--radius);
  border:1px solid var(--brand-2);background:var(--brand-2);color:#fff;
  transition:transform var(--quick) var(--ease),filter var(--quick),
             box-shadow var(--quick) var(--ease);
  /* Never below 44px of tappable height on a phone. */
  min-height:44px;
}
button.btn:hover{filter:brightness(1.07);box-shadow:var(--shadow)}
button.btn:active{transform:translateY(1px)}
button.btn:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}
button.btn.ghost{background:transparent;color:var(--brand-3);border-color:var(--line)}
button.btn.quiet{background:var(--line-soft);color:var(--ink);border-color:var(--line)}
/* --danger, not --red: one is a surface with white text on it, the other is
   ink. See the note in the theme code. */
button.btn.wrong{background:var(--danger);border-color:var(--danger)}
button.btn.small{padding:6px 12px;min-height:36px;font-size:.88rem}
.btns{display:flex;gap:8px;flex-wrap:wrap}

.err{
  background:var(--red-wash);color:var(--red);border:1px solid var(--red);
  border-radius:var(--radius);padding:10px 12px;margin-bottom:12px;font-size:.9rem;
}
.note{
  background:var(--accent-wash);border:1px solid var(--accent);
  border-radius:var(--radius);padding:10px 12px;font-size:.9rem;
}
.empty{
  text-align:center;color:var(--muted);padding:36px 16px;
  border:1px dashed var(--line);border-radius:var(--radius-lg);
}
.skeleton{
  height:64px;border-radius:var(--radius);margin-bottom:8px;
  background:linear-gradient(90deg,var(--line-soft),var(--line),var(--line-soft));
  background-size:200% 100%;animation:slide 1.2s infinite linear;
}
@keyframes slide{from{background-position:200% 0}to{background-position:-200% 0}}

/* ---------------------------------------------------------------- tables */

.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table{border-collapse:collapse;width:100%;font-size:.9rem}
/* A table narrower than its content does not get narrower, it gets taller —
   every cell wraps to one word a line and a date becomes five rows deep. So
   it keeps a sensible width and the wrapper scrolls sideways instead. The
   page body must never do that; only this box. */
.tablewrap table{min-width:560px}
.tablewrap td,.tablewrap th{white-space:nowrap}
.tablewrap td.wrap{white-space:normal;min-width:180px}
th,td{text-align:left;padding:9px 10px;border-bottom:1px solid var(--line-soft)}
th{color:var(--muted);font-weight:600;font-size:.8rem;text-transform:uppercase;
   letter-spacing:.04em;white-space:nowrap}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}
tbody tr:hover{background:var(--line-soft)}

/* ---------------------------------------------------------------- chat */

.chatwrap{display:grid;grid-template-columns:280px 1fr;gap:12px;min-height:60vh}
@media (max-width:760px){
  .chatwrap{grid-template-columns:1fr}
  .chatwrap.open .threadlist{display:none}
  .chatwrap:not(.open) .thread{display:none}
}
.threadlist{border:1px solid var(--line);border-radius:var(--radius-lg);
            background:var(--panel);overflow:auto;max-height:70vh}
.threadlist .item{
  display:flex;gap:10px;padding:10px 12px;cursor:pointer;
  border-bottom:1px solid var(--line-soft);align-items:center;
}
.threadlist .item.on{background:var(--accent-wash)}
.thread{display:flex;flex-direction:column;border:1px solid var(--line);
        border-radius:var(--radius-lg);background:var(--panel);min-height:60vh}
.thread .head{padding:10px 14px;border-bottom:1px solid var(--line);
              display:flex;gap:10px;align-items:center}
.msgs{flex:1;overflow:auto;padding:14px;display:flex;flex-direction:column;gap:8px;
      max-height:52vh}
.bubble{
  max-width:min(78%,520px);padding:9px 13px;border-radius:var(--radius-lg);
  background:var(--line-soft);align-self:flex-start;white-space:pre-wrap;
  word-break:break-word;
}
.bubble.me{background:var(--brand-2);color:#fff;align-self:flex-end}
.bubble.system{
  align-self:center;background:var(--accent-wash);color:var(--accent-deep);
  font-size:.84rem;text-align:center;max-width:90%;
}
.bubble time{display:block;font-size:.7rem;opacity:.7;margin-top:3px}
.composer{display:flex;gap:8px;padding:10px;border-top:1px solid var(--line)}
.composer textarea{min-height:44px;max-height:120px}

/* ---------------------------------------------------------------- grid of times */

.week{display:grid;grid-template-columns:repeat(7,1fr);gap:6px}
.week .day{border:1px solid var(--line);border-radius:var(--radius);padding:8px;
           background:var(--panel)}
.week .day h4{margin:0 0 6px;font-size:.78rem;color:var(--muted);text-transform:uppercase}
.slot{
  display:block;width:100%;text-align:left;margin-bottom:4px;
  padding:8px 10px;border-radius:var(--radius);cursor:pointer;
  border:1px solid var(--line);background:var(--panel);font:inherit;font-size:.86rem;
  transition:border-color var(--quick) var(--ease),background var(--quick) var(--ease);
}
.slot:hover{border-color:var(--brand-3);background:var(--accent-wash)}
.slot.on{background:var(--brand-2);color:#fff;border-color:var(--brand-2)}

/* ---------------------------------------------------------------- modal */

.veil{
  position:fixed;inset:0;background:rgba(4,46,36,.55);z-index:60;
  display:grid;place-items:center;padding:16px;
  animation:fade var(--quick) var(--ease);
}
@keyframes fade{from{opacity:0}to{opacity:1}}
.modal{
  background:var(--panel);border-radius:var(--radius-xl);
  box-shadow:var(--shadow-lift);width:min(560px,100%);
  max-height:88vh;overflow:auto;padding:20px;
}
.modal h2{margin-bottom:10px}
.modal .foot{display:flex;gap:8px;justify-content:flex-end;margin-top:16px}
.lead{display:flex;gap:12px;align-items:flex-start;margin-bottom:12px}
.lead .glyph{font-size:1.6rem;line-height:1}

#toasts{position:fixed;left:0;right:0;bottom:16px;z-index:80;
        display:flex;flex-direction:column;align-items:center;gap:8px;
        pointer-events:none}
.toast{
  background:var(--brand);color:#fff;padding:10px 16px;
  border-radius:var(--radius-pill);box-shadow:var(--shadow-lift);
  font-size:.9rem;max-width:90vw;
  animation:rise var(--calm) var(--ease);
}
.toast.gone{opacity:0;transition:opacity var(--calm)}
.toast.bad{background:var(--danger)}
.toast.good{background:var(--green)}
@keyframes rise{from{transform:translateY(12px);opacity:0}}

/* ---------------------------------------------------------------- quiz */

.qitem{border:1px solid var(--line);border-radius:var(--radius-lg);
       padding:14px;background:var(--panel);margin-bottom:10px}
.qitem .stem{font-weight:600;margin-bottom:10px;white-space:pre-wrap}
.opt{display:flex;gap:10px;align-items:flex-start;padding:9px 11px;
     border:1px solid var(--line);border-radius:var(--radius);
     margin-bottom:6px;cursor:pointer;background:var(--panel)}
.opt:hover{border-color:var(--brand-3)}
.opt.on{border-color:var(--brand-2);background:var(--accent-wash)}
.opt input{width:auto;flex:none;margin:3px 0 0}
.opt.right{border-color:var(--green);background:var(--green-wash)}
.opt.wrong{border-color:var(--red);background:var(--red-wash)}
.timer{font-variant-numeric:tabular-nums;font-weight:700}
.timer.low{color:var(--red)}
.bar{height:8px;background:var(--line-soft);border-radius:var(--radius-pill);
     overflow:hidden}
.bar i{display:block;height:100%;background:var(--brand-2)}

/* ---------------------------------------------------------------- splash */

.splash{
  position:fixed;inset:0;z-index:90;color:#fff;
  /* Two steps of the brand rather than one flat slab. */
  background:linear-gradient(160deg,var(--brand-2),var(--brand) 70%);
  display:grid;place-items:center;text-align:center;cursor:pointer;
}
.splash .crest{
  width:132px;height:132px;border-radius:var(--radius-pill);
  /* Artwork in the brand colour, on the brand colour, loses everything but
     the accent. It goes on a pale medallion — and a fixed one, for the same
     reason as the bar: this sits on the brand gradient in both themes. */
  background:#FFF6E3;color:var(--brand);
  display:grid;place-items:center;
  margin:0 auto 20px;box-shadow:var(--shadow-lift);
}
.splash .crest svg{width:88px;height:88px;display:block}
.splash .bar{width:180px;margin:16px auto 0;background:rgba(255,255,255,.22)}
.splash .bar i{background:var(--accent);width:0;animation:fill 3s linear forwards}
@keyframes fill{to{width:100%}}

/* The signed-out medallion, which sits on the page rather than on the bar. */
.gate-crest{
  width:76px;height:76px;border-radius:var(--radius-pill);
  background:var(--brand);color:#FFF6E3;display:grid;place-items:center;
  margin:0 auto 12px;box-shadow:var(--shadow);
}
.gate-crest svg{width:48px;height:48px;display:block}

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
}

@media print{
  .topbar,.tabs,.btns,#toasts{display:none !important}
  body{background:#fff}
  .card{box-shadow:none;border-color:#999}
}
