/* Thinqly component styles — extracted verbatim from Prototype.html.
   Only components used by built screens are carried over; further blocks
   (onboarding, homework, feedback…) get lifted from the prototype as their
   ROADMAP phase lands. */

/* Shell */
#app{max-width:760px; margin:0 auto; min-height:100vh; display:flex; flex-direction:column;}
.topbar{position:sticky; top:0; z-index:40; background:rgba(251,252,254,.92); backdrop-filter:blur(8px);
  border-bottom:1px solid var(--line); padding:calc(10px + env(safe-area-inset-top)) 16px 10px;
  display:flex; align-items:center; gap:10px;}
.wordmark{font-family:var(--display); font-weight:700; font-size:22px; letter-spacing:-.02em; color:var(--ink);}
.topbar .brandrow{display:flex; align-items:center; gap:8px;}
.topbar .spacer{flex:1;}
.mode-pill{border:1px solid var(--line); background:var(--card); border-radius:999px; padding:6px 12px; font-size:13px; font-weight:600; color:var(--ink-soft); display:flex; align-items:center; gap:6px; min-height:34px;}
.mode-pill.on{background:var(--accent); border-color:var(--accent); color:#fff;}
.iconbtn{border:1px solid var(--line); background:var(--card); border-radius:999px; width:38px; height:38px; display:flex; align-items:center; justify-content:center; color:var(--ink-soft);}
.iconbtn:focus-visible,.btn:focus-visible,.tab:focus-visible,.chip:focus-visible{outline:3px solid rgba(46,94,168,.4); outline-offset:2px;}
main{flex:1; padding:18px 16px 96px;}

/* Tabs */
.tabbar{position:fixed; bottom:0; left:0; right:0; z-index:40; background:rgba(255,255,255,.96); backdrop-filter:blur(8px);
  border-top:1px solid var(--line); display:flex; justify-content:center; padding:6px 8px calc(6px + env(safe-area-inset-bottom));}
.tabbar-inner{display:flex; width:100%; max-width:760px;}
.tab{flex:1; background:none; border:none; display:flex; flex-direction:column; align-items:center; gap:2px; padding:6px 2px; color:var(--ink-faint); font-size:11px; font-weight:600; border-radius:10px; min-height:48px;}
.tab svg{width:22px; height:22px;}
.tab.active{color:var(--accent);}
.tab:active{background:var(--accent-tint);}

/* Cards & layout atoms */
.card{background:var(--card); border:1px solid var(--line); border-radius:var(--r); padding:16px; box-shadow:var(--sh); margin-bottom:14px;}
.card.flat{box-shadow:none;}
.row{display:flex; align-items:center; gap:10px;}
.row.between{justify-content:space-between;}
.stack{display:flex; flex-direction:column; gap:10px;}
.grid2{display:grid; grid-template-columns:1fr 1fr; gap:10px;}
@media(max-width:480px){.grid2{grid-template-columns:1fr;}}

/* Buttons */
.btn{border:none; border-radius:999px; padding:12px 20px; font-size:15px; font-weight:600; min-height:44px; display:inline-flex; align-items:center; justify-content:center; gap:8px; transition:transform .12s ease, background .15s ease;}
.btn:active{transform:scale(.97);}
.btn.primary{background:var(--accent); color:#fff;}
.btn.primary:hover{background:var(--accent-deep);}
.btn.ghost{background:var(--card); border:1px solid var(--line); color:var(--ink);}
.btn.soft{background:var(--accent-tint); color:var(--accent-deep);}
.btn.danger{background:var(--red-tint); color:var(--red);}
.btn.sm{padding:8px 14px; font-size:13px; min-height:36px;}
.btn.block{width:100%;}
.btn[disabled]{opacity:.5; pointer-events:none;}
.btn .spin{width:16px;height:16px;border:2px solid rgba(255,255,255,.4);border-top-color:#fff;border-radius:50%;animation:sp .7s linear infinite;}
@keyframes sp{to{transform:rotate(360deg)}}

/* Chips */
.chips{display:flex; flex-wrap:wrap; gap:8px;}
.chip{border:1px solid var(--line); background:var(--card); border-radius:999px; padding:9px 15px; font-size:14px; font-weight:500; color:var(--ink); min-height:38px;}
.chip.on{background:var(--accent); border-color:var(--accent); color:#fff;}
.chip.small{padding:5px 11px; font-size:12.5px; min-height:28px;}
/* Group consent slice 4: a student who cannot be logged. Visibly inert rather
   than hidden — the tutor must see the student is there and why they are
   unavailable, or the roll looks wrong and the app looks broken. The reason
   text sits under the picker; this is only the affordance. */
.chip.blocked{background:var(--line-soft); border-color:var(--line-soft); color:var(--ink-faint);
  cursor:not-allowed; text-decoration:line-through; text-decoration-thickness:1px;}
.tag{display:inline-block; background:var(--accent-tint); color:var(--accent-deep); border-radius:6px; padding:2px 8px; font-size:12px; font-weight:600; font-family:var(--mono);}
.tag.red{background:var(--red-tint); color:var(--red);}
.tag.gold{background:var(--hl-soft); color:#7A6A10;}

/* Forms */
.field{margin-bottom:14px;}
.field label{display:block; font-size:13.5px; font-weight:600; margin-bottom:6px; color:var(--ink);}
.field .hint{font-size:12.5px; color:var(--ink-faint); margin-top:4px;}
.input, textarea.input{width:100%; border:1px solid var(--line); border-radius:var(--r-sm); padding:11px 13px; background:var(--card);}
.input:focus{outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-tint);}
textarea.input{resize:vertical; min-height:88px; line-height:1.5;}

/* Onboarding (login, consent) — lifted verbatim from Prototype.html */
.ob-wrap{max-width:520px; margin:0 auto; padding:36px 0 20px;}
.ob-progress{display:flex; gap:6px; margin-bottom:28px;}
.ob-progress span{flex:1; height:4px; border-radius:2px; background:var(--line);}
.ob-progress span.done{background:var(--accent);}
.ob-title{font-size:30px; font-weight:700; letter-spacing:-.02em; margin-bottom:8px;}
.ob-sub{color:var(--ink-soft); margin-bottom:24px;}

/* Chat */
.chat-wrap{display:flex; flex-direction:column; min-height:calc(100vh - 210px);}
.msgs{flex:1; display:flex; flex-direction:column; gap:12px; padding-bottom:12px;}
.msg{max-width:86%; padding:11px 15px; border-radius:16px; font-size:15px; line-height:1.5; white-space:pre-wrap; word-wrap:break-word;}
.msg.user{align-self:flex-end; background:var(--accent); color:#fff; border-bottom-right-radius:5px;}
.msg.ai{align-self:flex-start; background:var(--card); border:1px solid var(--line); border-bottom-left-radius:5px;}
.msg.ai b{font-weight:650;}
.msg img{max-width:180px; border-radius:8px; display:block; margin-top:6px;}
.msg .who{font-family:var(--mono); font-size:10.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--accent); margin-bottom:3px; font-weight:600;}
.typing{align-self:flex-start; display:flex; gap:4px; padding:14px 16px;}
.typing i{width:7px; height:7px; border-radius:50%; background:var(--ink-faint); animation:blink 1.2s infinite;}
.typing i:nth-child(2){animation-delay:.2s;} .typing i:nth-child(3){animation-delay:.4s;}
@keyframes blink{0%,60%,100%{opacity:.25}30%{opacity:1}}
.composer{position:sticky; bottom:70px; background:var(--card); border:1px solid var(--line); border-radius:22px; padding:8px; display:flex; align-items:flex-end; gap:6px; box-shadow:var(--sh);}
.composer textarea{flex:1; border:none; background:none; resize:none; padding:8px 6px; max-height:120px; font-size:15px;}
.composer textarea:focus{outline:none;}
.composer .iconbtn{border:none; flex-shrink:0;}
.composer .send{background:var(--accent); color:#fff;}

/* Thinqly bar */
.inq-bar{display:flex; align-items:center; gap:8px; margin:0 0 10px; padding:9px 13px; background:var(--card); border:1.5px solid var(--line); border-radius:12px; font-size:14px;}

/* Upload progress (video) — mastery-bar lifted from the prototype */
.mastery-bar{height:10px; border-radius:5px; background:var(--line-soft); overflow:hidden; margin-top:6px;}
.mastery-bar i{display:block; height:100%; background:var(--accent); border-radius:5px; transition:width .5s ease;}

/* Transcript block (homework photo answers) — the surviving record once the
   photo auto-deletes, so it must be READ, not skimmed */
.transcript-block{border:1.5px solid var(--accent); border-left-width:4px; border-radius:0 var(--r-sm) var(--r-sm) 0; background:var(--accent-tint); padding:10px 13px; margin:8px 0;}
.transcript-title{font-family:var(--mono); font-size:11px; letter-spacing:.1em; text-transform:uppercase; color:var(--accent-deep); font-weight:600; margin-bottom:6px;}
.transcript-text{font-size:14.5px; white-space:pre-wrap; line-height:1.5;}
.feedback-warn{border-color:var(--red) !important; box-shadow:0 0 0 3px var(--red-tint) !important;}
/* Photo-quality flag (Fix 1) — loud, so a tutor can't rubber-stamp a verdict
   built from a photo Thinqly couldn't fully see */
.photo-flag{border:1.5px solid var(--red); border-left-width:4px; background:var(--red-tint); color:var(--red); border-radius:0 var(--r-sm) var(--r-sm) 0; padding:9px 12px; margin:8px 0; font-size:14px;}
.suggested-block{margin-top:6px;}

/* Tab badge — in-app marker counts (review queue / new results) */
.tab-badge{position:absolute; top:2px; right:calc(50% - 22px); background:var(--red); color:#fff; font-size:10.5px; font-weight:700; min-width:16px; height:16px; border-radius:8px; display:flex; align-items:center; justify-content:center; padding:0 4px; font-family:var(--mono);}

/* Capture-confirm (student photo answers) — the student checks framing before
   submitting. Buttons are deliberately EQUAL weight: making "Use this photo"
   the obvious primary is how you get reflexive tapping, and the framing
   question needs to actually register for a beat. */
.confirm-img{width:100%; max-height:55vh; object-fit:contain; display:block;
  border:1px solid var(--line); border-radius:var(--r-sm); background:var(--line-soft);}
.confirm-ask{margin:12px 0; padding:10px 13px; border-left:4px solid var(--accent);
  background:var(--accent-tint); border-radius:0 var(--r-sm) var(--r-sm) 0; font-size:15px;}
.confirm-actions{display:flex; gap:10px;}
.confirm-actions .btn{flex:1 1 0; min-height:50px; font-size:15px;}  /* 1 1 0: content must not tilt the widths */
/* .btn.ghost carries a 1px border and .btn.soft doesn't; with flex-basis:0 that
   makes the bordered one 2px wider. Match it (invisible against soft's own fill)
   so the two read as exactly equal weight. */
.confirm-actions .btn.soft{border:1px solid var(--accent-tint);}

/* Memos (core loop, slice 1) */
.memo-h{font-family:var(--display); font-weight:700; font-size:15.5px; margin:14px 0 4px;}
/* A single formula must never widen the page. `\rule{9999em}{1em}` is ordinary
   TeX and NOT one of the commands trust:false blocks, so a model-generated or
   tutor-pasted memo can legitimately contain one — measured at 175,432px, which
   made the entire document scroll sideways.

   The guard goes on the CONTAINER, not on `.katex`. `.katex` is an inline
   element, so max-width and overflow do not apply to it at all; and forcing it
   to inline-block with overflow would move its baseline to the bottom margin
   edge and misalign every ordinary inline formula. Letting the line scroll keeps
   normal maths sitting correctly on the text baseline. */
.memo-p, .memo-h, .memo-h3, li{max-width:100%; overflow-x:auto; overflow-wrap:anywhere;}
/* Sub-heading. The prompt has always asked for these; until now they reached
   the student as literal "### " characters because the renderer only knew '## '. */
.memo-h3{font-family:var(--display); font-weight:600; font-size:14px; color:var(--ink-soft); margin:12px 0 3px;}
.memo-p + ul, .memo-p + ol, .memo-h + ul, .memo-h + ol, .memo-h3 + ul, .memo-h3 + ol{margin-top:4px;}
.memo-p ~ ul, .memo-p ~ ol{margin-bottom:8px;}
ul, ol{margin:0 0 8px; padding-left:22px;}
li{font-size:14.5px; line-height:1.55; margin-bottom:3px;}
li > ul, li > ol{margin:3px 0 0;}
li code{background:var(--line-soft); border-radius:4px; padding:1px 5px; font-family:var(--mono); font-size:13px;}
.memo-p{margin:0 0 8px; font-size:14.5px; line-height:1.55;}
.memo-p code{background:var(--line-soft); border-radius:4px; padding:1px 5px; font-family:var(--mono); font-size:13px;}
/* Shown when enrichment's response was malformed and the memo was salvaged.
   The sign-off gate only works if it knows what to look at — a degraded parse
   is stated here rather than left for the tutor to notice. */
.warn-banner{display:flex; flex-direction:column; gap:3px; background:#FDF4E3; border-left:3px solid var(--warn); border-radius:var(--r-sm); padding:10px 12px; margin-bottom:12px;}
.warn-banner b{font-size:13.5px; color:var(--warn);}
.warn-banner span{font-size:13px; line-height:1.5; color:var(--ink-soft);}
.session-row{margin-bottom:10px;}
.session-row:active{background:var(--accent-tint);}

/* Toast + modal */
#toast{position:fixed; bottom:92px; left:50%; transform:translateX(-50%) translateY(20px); background:var(--ink); color:#fff; padding:11px 18px; border-radius:999px; font-size:14px; opacity:0; pointer-events:none; transition:all .25s ease; z-index:60; max-width:88%; text-align:center;}
#toast.show{opacity:1; transform:translateX(-50%) translateY(0);}
.overlay{position:fixed; inset:0; background:rgba(16,28,48,.5); z-index:50; display:flex; align-items:flex-end; justify-content:center;}
@media(min-width:600px){.overlay{align-items:center;}}
.sheet{background:var(--card); border-radius:18px 18px 0 0; width:100%; max-width:560px; max-height:88vh; overflow-y:auto; padding:20px;}
@media(min-width:600px){.sheet{border-radius:18px;}}
.sheet h3{margin-bottom:12px;}
.loading-inline{display:flex; align-items:center; gap:10px; color:var(--ink-soft); font-size:14px; padding:14px 0;}
.loading-inline .spin{width:18px;height:18px;border:2.5px solid var(--line);border-top-color:var(--accent);border-radius:50%;animation:sp .7s linear infinite;}
.empty{padding:28px 12px; text-align:center; color:var(--ink-soft);}
.empty svg{width:34px; height:34px; color:var(--ink-faint); margin-bottom:8px;}

/* Login screen polish — scoped to .login-* classes only; other screens
   untouched. Same tokens, same brand: card elevation uses a brand-blue
   tinted shadow (never pure black), error callout reuses the prototype's
   red left-border margin-note language, entrance motion is one gentle
   rise with a reduced-motion guard. */
.login-screen{min-height:calc(100dvh - 76px); display:flex; flex-direction:column; align-items:center; justify-content:center; padding:24px 0;}
.login-card{width:100%; max-width:420px; background:var(--card); border:1px solid var(--line); border-radius:var(--r);
  padding:30px 28px 24px;
  box-shadow:0 1px 2px rgba(27,41,64,.05), 0 3px 12px rgba(27,41,64,.05), 0 18px 48px -18px rgba(46,94,168,.22);}
.login-brand{display:flex; align-items:center; gap:10px; margin-bottom:20px;}
.login-brand svg{width:40px; height:40px;}
.login-card .ob-title{font-size:26px;}
.login-card .ob-sub{font-size:14.5px; margin-bottom:20px;}
.login-card .input{padding:12px 14px;}
.login-card .input::placeholder{color:var(--ink-faint);}
.login-err{border-left:3px solid var(--red); background:var(--red-tint); border-radius:0 var(--r-sm) var(--r-sm) 0;
  padding:10px 13px; font-size:13.5px; color:var(--red); margin-bottom:16px;}
.login-alt{text-align:center; margin:16px 0 0; font-size:13.5px;}
.login-foot{margin-top:18px; font-size:12.5px; color:var(--ink-faint); text-align:center; max-width:340px;}
@keyframes login-rise{from{opacity:0; transform:translateY(14px)} to{opacity:1; transform:none}}
.login-card{animation:login-rise .45s cubic-bezier(.16,1,.3,1) both;}
.login-foot{animation:login-rise .45s .08s cubic-bezier(.16,1,.3,1) both;}

@media (prefers-reduced-motion:reduce){.btn{transition:none;} .typing i{animation:none;} .login-card,.login-foot{animation:none;}}

/* ── Consent screens ────────────────────────────────────────────────────────
   The six consent points are long by necessity — they are verbatim legal text,
   not UI copy, so they cannot be trimmed to fit. These rules make a wall of
   required reading legible rather than shorter: a rule between points so they
   read as six separate things to agree to (which is the legal shape), and a
   tick target that stays put beside the first line instead of centring itself
   against a five-line paragraph. */
.consent-point{gap:10px; border-bottom:1px solid var(--line-soft);}
.consent-point:last-of-type{border-bottom:0;}
.consent-point span{line-height:1.55;}
.consent-point input[type=checkbox]{width:19px; height:19px; accent-color:var(--accent);}

/* The full Privacy Notice, collapsed by default. It forms part of the consent,
   so it is present on the screen and one tap away — but ~2,000 words shown
   open by default pushes the actual tick boxes off the bottom, and a consent
   nobody scrolled to is a weak consent. */
.legal-details{padding:0;}
.legal-details > summary{cursor:pointer; padding:14px 16px; font-size:13.5px; font-weight:600;
  color:var(--accent); list-style:none;}
.legal-details > summary::-webkit-details-marker{display:none;}
.legal-details > summary::after{content:' ▾'; color:var(--ink-faint);}
.legal-details[open] > summary::after{content:' ▴';}
.legal-details > summary:focus-visible{outline:3px solid rgba(46,94,168,.4); outline-offset:-3px;}
.legal-full{max-height:46vh; overflow-y:auto; padding:0 16px 16px; border-top:1px solid var(--line-soft);
  -webkit-overflow-scrolling:touch;}
.legal-full p:first-child{margin-top:12px;}
