DavidL72Code/UMB_Sustainable_Chatbot
0
1:root {2 --bg: #f0f5fb;3 --panel: #ffffff;4 --header-bg: #132245;5 --header-bg-alt: #005A8B;6 --brand: #005A8B;7 --brand-dark: #132245;8 --brand-light: #DDEBF9;9 --accent: #FEDE42;10 --text: #201F1F;11 --muted: #5A5A5A;12 --line: #DEDEDE;13 --user-bubble: #DDEBF9;14 --assistant-bubble: #ffffff;15 --shadow: 0 4px 24px rgba(19, 34, 69, 0.10);16 --shadow-header: 0 2px 12px rgba(19, 34, 69, 0.18);17}18 19* {20 box-sizing: border-box;21}22 23body {24 margin: 0;25 height: 100vh;26 display: flex;27 flex-direction: column;28 font-family: "Inter", sans-serif;29 color: var(--text);30 background: var(--bg);31 overflow: hidden;32}33 34/* ── Header ── */35.site-header {36 background: linear-gradient(135deg, var(--header-bg) 0%, var(--header-bg-alt) 50%, var(--header-bg) 100%);37 background-size: 200% 100%;38 animation: gradient-slide 16s ease-in-out infinite;39 box-shadow: var(--shadow-header);40 padding: 0 32px;41 border-bottom: 2px solid var(--accent);42}43 44.header-inner {45 display: flex;46 align-items: center;47 gap: 16px;48 max-width: 1100px;49 margin: 0 auto;50 padding: 18px 0;51 user-select: none;52}53 54.header-umb-logo {55 height: 36px;56 width: auto;57 filter: brightness(0) invert(1);58 flex-shrink: 0;59}60 61.header-logo {62 display: flex;63 flex-direction: column;64 gap: 2px;65}66 67.header-logo-name {68 font-family: "Lora", serif;69 font-size: 22px;70 font-weight: 700;71 color: #ffffff;72 letter-spacing: 0.01em;73 line-height: 1.1;74}75 76.header-logo-tagline {77 font-size: 12px;78 font-weight: 400;79 color: rgba(255, 255, 255, 0.72);80 letter-spacing: 0.06em;81 text-transform: uppercase;82}83 84.header-divider {85 width: 1px;86 height: 36px;87 background: rgba(255, 255, 255, 0.22);88 margin: 0 4px;89}90 91.header-tool-label {92 font-size: 13px;93 color: rgba(255, 255, 255, 0.6);94 letter-spacing: 0.04em;95}96 97.header-links {98 margin-left: auto;99 display: flex;100 align-items: center;101 gap: 8px;102}103 104.header-ssl-link {105 /* Keeps "Sign in" on one line; the narrow-screen padding otherwise wraps it. */106 white-space: nowrap;107 font-size: 13px;108 font-weight: 600;109 color: var(--header-bg);110 text-decoration: none;111 background: var(--accent);112 border: 1px solid var(--accent);113 border-radius: 999px;114 padding: 6px 14px;115 transition: background 130ms ease, color 130ms ease;116}117 118.header-ssl-link:hover {119 background: #e8cc2a;120 border-color: #e8cc2a;121}122 123/* ── Main shell ── */124.shell {125 width: min(1100px, calc(100vw - 32px));126 margin: 0 auto;127 padding: 14px 0 10px;128 flex: 1;129 display: flex;130 flex-direction: column;131 min-height: 0;132}133 134.chat-layout {135 display: flex;136 flex: 1;137 gap: 16px;138 min-height: 0;139}140 141/* ── Sidebar ── */142.sidebar {143 width: 220px;144 flex-shrink: 0;145 display: flex;146 flex-direction: column;147 background: var(--panel);148 border: 1px solid var(--line);149 border-radius: 12px;150 box-shadow: var(--shadow);151 overflow: hidden;152}153 154.sidebar-header {155 padding: 14px 16px;156 font-size: 11px;157 font-weight: 600;158 letter-spacing: 0.07em;159 text-transform: uppercase;160 color: #ffffff;161 background: linear-gradient(135deg, var(--header-bg) 0%, var(--header-bg-alt) 100%);162 flex-shrink: 0;163}164 165.sidebar-list {166 list-style: none;167 margin: 0;168 padding: 8px 0;169 overflow-y: auto;170 flex: 1;171}172 173.sidebar-empty {174 padding: 12px 16px;175 font-size: 12px;176 color: #aab4be;177 font-style: italic;178}179 180.sidebar-item {181 padding: 0;182}183 184.sidebar-link {185 width: 100%;186 display: block;187 border: 0;188 background: transparent;189 padding: 9px 16px;190 font: inherit;191 font-size: 13px;192 color: var(--text);193 cursor: pointer;194 border-left: 3px solid transparent;195 line-height: 1.4;196 transition: background 120ms ease, border-color 120ms ease, color 120ms ease;197 white-space: nowrap;198 overflow: hidden;199 text-overflow: ellipsis;200 text-align: left;201}202 203.sidebar-link:hover {204 background: var(--brand-light);205 border-left-color: var(--accent);206 color: var(--brand-dark);207}208 209/* ── Hero ── */210.hero {211 padding: 0 4px 12px;212 border-bottom: 1px solid var(--line);213 margin-bottom: 12px;214 flex-shrink: 0;215}216 217.hero h1 {218 margin: 0 0 4px;219 font-family: "Lora", serif;220 font-size: clamp(18px, 2.2vw, 26px);221 font-weight: 700;222 color: var(--brand-dark);223 line-height: 1.15;224}225 226.hero-copy {227 margin: 0;228 font-size: 13px;229 color: var(--muted);230 line-height: 1.5;231 max-width: 680px;232}233 234/* ── Chat card ── */235.chat-card {236 display: flex;237 flex-direction: column;238 flex: 1;239 min-height: 0;240 border: 1px solid var(--line);241 border-radius: 12px;242 background: var(--panel);243 box-shadow: var(--shadow);244 overflow: hidden;245}246 247.chat-card-header {248 display: flex;249 align-items: center;250 gap: 10px;251 padding: 14px 20px;252 background: linear-gradient(135deg, var(--header-bg) 0%, var(--header-bg-alt) 50%, var(--header-bg) 100%);253 background-size: 200% 100%;254 animation: gradient-slide 16s ease-in-out infinite;255 border-bottom: none;256}257 258.status-dot {259 width: 9px;260 height: 9px;261 border-radius: 50%;262 background: #28a745;263 flex-shrink: 0;264 transition: background 200ms ease;265}266 267.status-dot.processing {268 background: #f59e0b;269 animation: blink-dot 800ms ease-in-out infinite;270}271 272@keyframes blink-dot {273 0%, 100% { opacity: 1; }274 50% { opacity: 0.25; }275}276 277.chat-card-title {278 font-size: 13px;279 font-weight: 600;280 color: #ffffff;281 letter-spacing: 0.02em;282}283 284/* ── Messages ── */285.chat-messages {286 flex: 1;287 padding: 24px 20px;288 overflow-y: auto;289 display: flex;290 flex-direction: column;291 gap: 20px;292}293 294.message {295 display: flex;296 flex-direction: column;297 gap: 6px;298 animation: rise-in 200ms ease;299}300 301.message.user {302 align-items: flex-end;303}304 305.message-label {306 display: flex;307 align-items: center;308 gap: 5px;309 font-size: 11px;310 font-weight: 600;311 color: var(--muted);312 letter-spacing: 0.07em;313 text-transform: uppercase;314 padding: 0 4px;315}316 317.assistant-icon {318 display: inline-flex;319 align-items: center;320 justify-content: center;321 width: 18px;322 height: 18px;323 color: var(--brand);324 flex-shrink: 0;325}326 327.assistant-icon svg {328 width: 14px;329 height: 14px;330}331 332.message-bubble {333 max-width: min(680px, 82%);334 padding: 13px 16px;335 border-radius: 10px;336 line-height: 1.6;337 white-space: pre-wrap;338 word-break: break-word;339 font-size: 15px;340}341 342.message-bubble p {343 margin: 0 0 10px;344}345 346.message-bubble p:last-child {347 margin-bottom: 0;348}349 350.bubble-link {351 color: var(--brand);352 text-decoration: underline;353 text-underline-offset: 2px;354 transition: color 130ms ease;355}356 357.bubble-link:hover {358 color: var(--brand-dark);359}360 361.message-bubble ul {362 margin: 6px 0 0;363 padding-left: 20px;364}365 366.message-bubble li + li {367 margin-top: 5px;368}369 370.message.assistant .message-bubble {371 background: var(--assistant-bubble);372 border: 1px solid var(--line);373 border-top-left-radius: 2px;374}375 376.message.user .message-bubble {377 background: var(--user-bubble);378 border: 1px solid #b9d4ee;379 border-top-right-radius: 2px;380 color: var(--brand-dark);381}382 383/* ── Sources ── */384.message-sources {385 display: flex;386 flex-wrap: wrap;387 gap: 6px;388 max-width: min(680px, 82%);389 padding: 0 2px;390}391 392.sources-label {393 width: 100%;394 font-size: 11px;395 font-weight: 600;396 color: var(--muted);397 letter-spacing: 0.06em;398 text-transform: uppercase;399}400 401.message-options {402 display: flex;403 flex-wrap: wrap;404 gap: 10px;405 max-width: min(700px, 84%);406}407 408.source-chip {409 display: inline-flex;410 align-items: center;411 gap: 5px;412 padding: 5px 11px;413 border-radius: 4px;414 border: 1px solid #b9d4ee;415 background: var(--brand-light);416 color: var(--brand-dark);417 text-decoration: none;418 font-size: 12px;419 font-weight: 500;420 transition: background 130ms ease, border-color 130ms ease;421}422 423.source-chip:hover {424 background: #c8ddf5;425 border-color: #93bde0;426}427 428.source-chip-disabled {429 opacity: 0.55;430 cursor: default;431 pointer-events: none;432}433 434.option-bubble {435 display: inline-flex;436 align-items: center;437 justify-content: flex-start;438 min-height: 42px;439 max-width: min(520px, 84vw);440 padding: 10px 15px;441 border-radius: 18px;442 border: 1px solid rgba(45, 106, 79, 0.18);443 background: rgba(255, 255, 255, 0.96);444 color: var(--text);445 font: inherit;446 text-align: left;447 cursor: pointer;448 box-shadow: 0 10px 24px rgba(45, 70, 54, 0.08);449 transition: transform 140ms ease, background 140ms ease, border-color 140ms ease;450}451 452.option-bubble:hover {453 background: #fff;454 border-color: rgba(45, 106, 79, 0.32);455 transform: translateY(-1px);456}457 458/* ── Suggested questions ── */459.suggested-questions {460 padding: 4px 2px 8px;461 display: flex;462 flex-direction: column;463 gap: 8px;464}465 466.suggested-label {467 font-size: 11px;468 font-weight: 600;469 color: var(--muted);470 letter-spacing: 0.06em;471 text-transform: uppercase;472 margin: 0;473}474 475.suggested-list {476 display: flex;477 flex-wrap: wrap;478 gap: 8px;479}480 481.suggested-btn {482 display: inline-flex;483 align-items: center;484 padding: 7px 14px;485 border-radius: 999px;486 border: 1px solid var(--brand);487 background: transparent;488 color: var(--brand);489 font: inherit;490 font-size: 13px;491 cursor: pointer;492 transition: background 130ms ease, color 130ms ease, border-color 130ms ease;493}494 495.suggested-btn:hover {496 background: var(--brand);497 color: #ffffff;498}499 500/* ── Composer ── */501.composer {502 display: flex;503 align-items: center;504 gap: 10px;505 padding: 14px 16px;506 border-top: 1px solid var(--line);507 background: #f8fafd;508}509 510.composer input {511 flex: 1;512 height: 48px;513 border: 1px solid var(--line);514 border-radius: 6px;515 padding: 0 16px;516 font: inherit;517 font-size: 15px;518 color: var(--text);519 background: #ffffff;520 transition: border-color 130ms ease, box-shadow 130ms ease;521}522 523.composer input::placeholder {524 color: #9aacbb;525}526 527.composer input:focus {528 outline: none;529 border-color: var(--brand);530 box-shadow: 0 0 0 3px rgba(0, 90, 139, 0.12);531}532 533.composer button {534 width: 48px;535 height: 48px;536 border: none;537 border-radius: 999px;538 background: var(--brand);539 color: white;540 cursor: pointer;541 flex-shrink: 0;542 transition: background 130ms ease, transform 130ms ease;543}544 545.composer button:hover {546 background: var(--brand-dark);547 box-shadow: 0 0 0 2px var(--accent);548}549 550.composer button:disabled {551 opacity: 0.55;552 cursor: wait;553 transform: none;554}555 556.send-arrow {557 display: inline-block;558 font-size: 22px;559 line-height: 1;560}561 562/* ── Loading dots ── */563.loading-bubble {564 display: inline-flex;565 align-items: center;566 gap: 7px;567 min-width: 70px;568}569 570.dot {571 width: 8px;572 height: 8px;573 border-radius: 50%;574 background: #93bde0;575 animation: pulse-dot 1.1s infinite ease-in-out;576}577 578.dot:nth-child(2) { animation-delay: 0.18s; }579.dot:nth-child(3) { animation-delay: 0.36s; }580 581/* ── Footer ── */582.site-footer {583 padding: 7px 32px;584 border-top: 2px solid #FF791F;585 background: #F5F0E6;586 display: flex;587 flex-direction: row;588 align-items: center;589 justify-content: center;590 gap: 16px;591 font-size: 11px;592 color: var(--brand-dark);593 flex-shrink: 0;594}595 596.footer-site-link {597 color: var(--brand-dark);598 text-decoration: none;599 transition: color 130ms ease;600}601 602.footer-site-link:hover {603 color: #FF791F;604}605 606.footer-credit {607 font-size: 11px;608 color: #8a8a8a;609 font-style: italic;610}611 612.footer-email-btn {613 font-size: 12px;614 font-weight: 500;615 color: var(--brand-dark);616 text-decoration: none;617 border: 1px solid var(--brand-dark);618 border-radius: 999px;619 padding: 5px 13px;620 transition: background 130ms ease, color 130ms ease;621}622 623.footer-email-btn:hover {624 background: var(--brand-dark);625 color: #ffffff;626}627 628/* ── Accessibility ── */629.sr-only {630 position: absolute;631 width: 1px;632 height: 1px;633 padding: 0;634 margin: -1px;635 overflow: hidden;636 clip: rect(0, 0, 0, 0);637 white-space: nowrap;638 border: 0;639}640 641/* ── Suggestion chips (dynamic follow-up questions) ── */642.suggestion-chips {643 display: flex;644 flex-direction: column;645 gap: 8px;646 padding: 10px 2px 2px;647 max-width: min(680px, 82%);648}649 650.suggestion-chips-label {651 font-size: 11px;652 font-weight: 600;653 color: var(--muted);654 letter-spacing: 0.06em;655 text-transform: uppercase;656 margin: 0;657}658 659.suggestion-chips-list {660 display: flex;661 flex-wrap: wrap;662 gap: 8px;663}664 665.suggestion-chip {666 display: inline-flex;667 align-items: center;668 padding: 7px 14px;669 border-radius: 999px;670 border: 1px solid var(--brand);671 background: transparent;672 color: var(--brand);673 font: inherit;674 font-size: 13px;675 cursor: pointer;676 transition: background 130ms ease, color 130ms ease;677}678 679.suggestion-chip:hover {680 background: var(--brand);681 color: #ffffff;682}683 684/* ── Animations ── */685@keyframes gradient-slide {686 0% { background-position: 0% 50%; }687 50% { background-position: 100% 50%; }688 100% { background-position: 0% 50%; }689}690 691@keyframes pulse-dot {692 0%, 100% { background: #b9d4ee; transform: scale(0.9); }693 40% { background: var(--brand); transform: scale(1.1); }694}695 696@keyframes rise-in {697 from { opacity: 0; transform: translateY(6px); }698 to { opacity: 1; transform: translateY(0); }699}700 701/* ── Responsive ── */702@media (max-width: 680px) {703 .site-header { padding: 0 16px; }704 .header-logo-name { font-size: 18px; }705 /* Keep the account controls on small screens. This was display:none, which706 removed Sign in along with everything else, so a visitor on a phone had no707 way to sign in or reach their saved history — the button was in the DOM708 and visible, inside a nav the browser was not painting. Only the external709 SSL link is dropped; it is repeated in the footer. */710 .header-links { gap: 6px; }711 .header-links a.header-ssl-link[href^="https://www.umb.edu"] { display: none; }712 .header-links .header-ssl-link { padding: 5px 10px; font-size: 12px; }713 .account-email { max-width: 96px; }714 715 .shell {716 width: calc(100vw - 16px);717 padding-top: 20px;718 }719 720 .hero { padding-bottom: 10px; margin-bottom: 10px; }721 722 .sidebar { display: none; }723 724 .chat-card { border-radius: 8px; }725 726 .chat-messages { padding: 16px 14px; }727 728 .message-bubble { max-width: 90%; font-size: 14px; }729 730 .composer { padding: 10px 12px; }731}732 733/* Optional visitor accounts: sign-in control and dialog. */734.account-area {735 display: inline-flex;736 align-items: center;737 gap: 10px;738}739 740/* An explicit display value beats the default [hidden] rule, so restate it.741 Without this the sign-in control shows on deployments that have no accounts742 configured. */743.account-area[hidden],744.account-email[hidden] {745 display: none;746}747 748.account-email {749 color: rgba(255, 255, 255, 0.85);750 font-size: 12px;751 font-weight: 600;752 max-width: 180px;753 overflow: hidden;754 text-overflow: ellipsis;755 white-space: nowrap;756}757 758/* Sidebar: new-chat control, active chat, delete affordance */759.sidebar-header {760 display: flex;761 align-items: center;762 justify-content: space-between;763 gap: 8px;764}765 766.sidebar-new {767 background: none;768 border: 1px solid rgba(19, 34, 69, 0.25);769 border-radius: 999px;770 padding: 2px 9px;771 font: inherit;772 font-size: 11px;773 font-weight: 700;774 color: var(--header-bg, #132245);775 cursor: pointer;776 white-space: nowrap;777}778 779.sidebar-new:hover { background: rgba(19, 34, 69, 0.08); }780 781.sidebar-item { display: flex; align-items: center; gap: 4px; }782.sidebar-item .sidebar-link { flex: 1; text-align: left; }783 784.sidebar-item.is-active {785 background: rgba(19, 34, 69, 0.08);786 border-radius: 8px;787}788 789.sidebar-delete {790 background: none;791 border: none;792 color: rgba(19, 34, 69, 0.45);793 font-size: 16px;794 line-height: 1;795 padding: 2px 6px;796 cursor: pointer;797 border-radius: 6px;798 opacity: 0;799 transition: opacity 120ms ease, color 120ms ease;800}801 802.sidebar-item:hover .sidebar-delete,803.sidebar-delete:focus-visible { opacity: 1; }804.sidebar-delete:hover { color: #b3261e; background: rgba(179, 38, 30, 0.1); }805 806/* Confirm-your-email dialog: its own box, shown after a successful signup. */807.notice-dialog { max-width: 380px; text-align: left; }808 809.notice-body {810 margin: 4px 0 18px;811 font-size: 14px;812 line-height: 1.5;813 color: rgba(19, 34, 69, 0.85);814}815 816.account-button {817 /* Match the yellow header pills. This used to be a transparent chip with a818 white border, and `font: inherit` also discarded the pill's 13px/600, so819 the control sat next to "Visit SSL" at a different size, weight and820 colour. A <button> only needs its native font and line-height neutralised;821 everything else comes from .header-ssl-link. */822 cursor: pointer;823 font-family: inherit;824 font-size: 13px;825 font-weight: 600;826 line-height: 1.2;827 -webkit-appearance: none;828 appearance: none;829}830 831.account-button:hover {832 background: rgba(255, 255, 255, 0.14);833}834 835.sidebar-note {836 margin: 10px 12px 0;837 color: #5b6472;838 font-size: 12px;839 line-height: 1.45;840}841 842.sidebar-item {843 display: flex;844 align-items: center;845 gap: 4px;846}847 848.sidebar-delete {849 flex: none;850 background: none;851 border: 0;852 color: #8b95a3;853 cursor: pointer;854 font-size: 18px;855 line-height: 1;856 padding: 2px 6px;857 border-radius: 6px;858}859 860.sidebar-delete:hover {861 background: #f0f2f6;862 color: #b3261e;863}864 865.auth-overlay {866 position: fixed;867 inset: 0;868 z-index: 50;869 display: flex;870 align-items: center;871 justify-content: center;872 padding: 20px;873 background: rgba(11, 26, 47, 0.55);874}875 876.auth-overlay[hidden] {877 display: none;878}879 880.auth-dialog {881 position: relative;882 width: 100%;883 max-width: 380px;884 padding: 24px;885 border-radius: 12px;886 background: #fff;887 box-shadow: 0 18px 48px rgba(11, 26, 47, 0.28);888}889 890.auth-dialog h2 {891 margin: 0 0 8px;892 font-size: 20px;893}894 895.auth-blurb {896 margin: 0 0 16px;897 color: #5b6472;898 font-size: 13px;899 line-height: 1.5;900}901 902.auth-dialog label {903 display: block;904 margin-bottom: 4px;905 font-size: 12px;906 font-weight: 700;907 color: #3d4757;908}909 910.auth-dialog input {911 width: 100%;912 margin-bottom: 12px;913 padding: 10px 12px;914 border: 1px solid #d4d9e1;915 border-radius: 8px;916 font: inherit;917 box-sizing: border-box;918}919 920.auth-dialog input:focus {921 outline: 2px solid #1b4a8a;922 outline-offset: 1px;923}924 925.auth-submit {926 width: 100%;927 padding: 11px;928 border: 0;929 border-radius: 8px;930 background: #1b4a8a;931 color: #fff;932 font: inherit;933 font-weight: 700;934 cursor: pointer;935}936 937.auth-submit:disabled {938 opacity: 0.6;939 cursor: progress;940}941 942.auth-error {943 margin: 0 0 12px;944 padding: 8px 10px;945 border-radius: 6px;946 background: #fdecea;947 color: #b3261e;948 font-size: 12px;949}950 951.auth-switch {952 margin: 14px 0 0;953 text-align: center;954 font-size: 12px;955 color: #5b6472;956}957 958.auth-switch button {959 background: none;960 border: 0;961 color: #1b4a8a;962 cursor: pointer;963 font: inherit;964 font-weight: 700;965 text-decoration: underline;966}967 968.auth-close {969 position: absolute;970 top: 8px;971 right: 10px;972 background: none;973 border: 0;974 color: #8b95a3;975 cursor: pointer;976 font-size: 22px;977 line-height: 1;978}979 980.auth-forgot {981 margin: 10px 0 0;982 text-align: center;983}984 985.auth-forgot button {986 background: none;987 border: 0;988 color: #5b6472;989 cursor: pointer;990 font: inherit;991 font-size: 12px;992 text-decoration: underline;993}994 995.auth-forgot[hidden],996.auth-forgot button[hidden] {997 display: none;998}999 1000.auth-field[hidden] {1001 display: none;1002}1003 1004/* ---- Warming notice -----------------------------------------------------1005 The Space sleeps after a quiet period and needs a few seconds to load its1006 index on the next visit. That is rare, so this stays hidden unless the1007 backend actually reports it -- no spinner flash for the usual warm case. */1008.warming-notice {1009 display: flex;1010 align-items: center;1011 gap: 9px;1012 margin: 0 16px 10px;1013 padding: 9px 13px;1014 border: 1px solid var(--line);1015 border-left: 3px solid var(--accent);1016 border-radius: 8px;1017 background: var(--brand-light);1018 color: var(--text);1019 font-size: 13px;1020}1021 1022.warming-notice[hidden] { display: none; }1023 1024.warming-spinner {1025 flex: none;1026 width: 13px;1027 height: 13px;1028 border: 2px solid rgba(0, 90, 139, 0.25);1029 border-top-color: var(--brand);1030 border-radius: 50%;1031 animation: warming-spin 750ms linear infinite;1032}1033 1034@keyframes warming-spin { to { transform: rotate(360deg); } }1035 1036.composer input:disabled,1037.composer button:disabled {1038 opacity: 0.55;1039 cursor: not-allowed;1040}1041 1042@media (prefers-reduced-motion: reduce) {1043 .warming-spinner { animation-duration: 2.4s; }1044}1045 