researchbee / ResearchBee_LibGuides.html
nikeshn's picture
Upload 52 files
0b82dd4 verified
Raw History Blame Contribute Delete
456 kB
<!-- ResearchBee for LibGuides: paste this entire fragment into an HTML/source-code area. -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&amp;family=PT+Sans:wght@700&amp;display=swap">
<style>
/* Native fonts keep the first render independent of external font services. */
#researchbee-app {
--primary: #2059A8;
--primary-dark: #174483;
--primary-light: #EBF1FA;
--primary-xlight: #F4F7FC;
--accent: #f59e0b;
--accent-light: #fef3c7;
--success: #059669;
--success-light: #d1fae5;
--warning: #d97706;
--warning-light: #fef3c7;
--danger: #dc2626;
--danger-light: #fee2e2;
--text: #111827;
--text-muted: #6b7280;
--text-light: #9ca3af;
--border: #e5e7eb;
--border-strong: #d1d5db;
--bg: #ffffff;
--bg-subtle: #f9fafb;
--shadow-sm: none;
--shadow: none;
--shadow-lg: none;
--radius: 0;
--radius-sm: 0;
--radius-lg: 0;
}
#researchbee-app *,
#researchbee-app *::before,
#researchbee-app *::after {
box-sizing: border-box; margin: 0; padding: 0;
}
#researchbee-app {
scroll-behavior: smooth;
}
#researchbee-app {
font-family: "Open Sans", Arial, sans-serif;
font-size: 15px; line-height: 1.6;
color: var(--text); background: var(--bg-subtle); min-height: 100vh;
}
#researchbee-app h1,
#researchbee-app h2,
#researchbee-app h3 {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; line-height: 1.2;
}
#researchbee-app .site-header {
background: #001B48;
color: white; position: relative; z-index: 100;
box-shadow: 0 2px 20px rgba(32,89,168,.4);
}
#researchbee-app .header-inner {
display: flex; align-items: center; justify-content: space-between;
padding: 14px 20px; max-width: 1100px; margin: 0 auto;
}
#researchbee-app .brand {
display: flex; align-items: center; gap: 10px; text-decoration: none; color: white;
}
#researchbee-app .brand-icon {
font-size: 24px;
}
#researchbee-app .brand-name {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; font-size: 20px;
}
#researchbee-app .brand-sub {
font-size: 11px; opacity: .7; display: block; margin-top: -2px;
}
#researchbee-app .header-links {
display: flex; gap: 6px;
}
#researchbee-app .header-link {
color: rgba(255,255,255,.8); font-size: 13px; text-decoration: none;
padding: 5px 10px; border-radius: 0 ; transition: all .2s;
}
#researchbee-app .header-link:hover {
background: rgba(255,255,255,.15); color: white;
}
#researchbee-app .model-bar {
background: rgba(0,0,0,.2); border-top: 1px solid rgba(255,255,255,.08);
}
#researchbee-app .model-bar-inner {
max-width: 1100px; margin: 0 auto; padding: 8px 20px;
display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
#researchbee-app .model-label {
font-size: 12px; color: rgba(255,255,255,.65); font-weight: 500;
}
#researchbee-app .model-toggle {
display: flex; gap: 4px;
}
#researchbee-app .model-btn {
padding: 4px 14px; border-radius: 0 ; border: 1px solid rgba(255,255,255,.25);
background: transparent; color: rgba(255,255,255,.75); font-size: 12px;
cursor: pointer; transition: all .2s; font-family: ui-monospace, monospace;
}
#researchbee-app .model-btn.active {
background: white; color: var(--primary); border-color: white; font-weight: 700;
}
#researchbee-app .model-btn:hover:not(.active) {
background: rgba(255,255,255,.15); color: white;
}
#researchbee-app .model-hint {
font-size: 11px; color: rgba(255,255,255,.45);
}
#researchbee-app .hero {
background: #001B48;
color: white; padding: 44px 20px 52px;
}
#researchbee-app .hero-inner {
max-width: 1100px; margin: 0 auto;
}
#researchbee-app .hero-eyebrow {
font-size: 11px; font-family: ui-monospace, monospace;
opacity: .65; margin-bottom: 10px; letter-spacing: .1em; text-transform: uppercase;
display: flex; align-items: center; gap: 6px;
}
#researchbee-app .hero h1 {
font-size: clamp(26px,5vw,42px); margin-bottom: 10px;
}
#researchbee-app .hero h1 span {
opacity: .7;
}
#researchbee-app .hero-tagline {
font-size: 16px; opacity: .85; max-width: 600px; line-height: 1.7; margin-bottom: 16px;
}
#researchbee-app .hero-ku {
display: flex; align-items: center; gap: 8px; opacity: .65; font-size: 13px;
}
#researchbee-app .hero-ku a {
color: rgba(255,255,255,.9); text-decoration: none;
}
#researchbee-app .hero-ku a:hover {
text-decoration: underline;
}
#researchbee-app .tabs-bar {
background: white; border-bottom: 2px solid var(--border);
position: sticky; top: 0; z-index: 90; box-shadow: var(--shadow-sm);
}
#researchbee-app .tabs-inner {
max-width: 1100px; margin: 0 auto; display: flex;
}
#researchbee-app .tab-btn {
display: flex; align-items: center; gap: 8px;
padding: 15px 22px; border: none; background: transparent;
color: var(--text-muted); font-size: 14px; font-weight: 500;
cursor: pointer; border-bottom: 3px solid transparent; margin-bottom: -2px;
transition: color .2s; font-family: "Open Sans", Arial, sans-serif;
}
#researchbee-app .tab-btn:hover {
color: var(--primary);
}
#researchbee-app .tab-btn.active {
color: var(--primary); border-bottom-color: var(--primary);
}
#researchbee-app .tab-icon {
font-size: 16px;
}
#researchbee-app .main-content {
padding: 28px 20px 60px; max-width: 1100px; margin: 0 auto;
}
#researchbee-app .tab-panel {
display: none !important;
}
#researchbee-app .tab-panel.active {
display: block !important;
}
#researchbee-app .card {
background: white; border: 1px solid var(--border);
border-radius: var(--radius-lg); box-shadow: var(--shadow); overflow: hidden;
}
#researchbee-app .card-header {
padding: 20px 24px; border-bottom: 1px solid var(--border);
background: #FFFFFF;
}
#researchbee-app .card-header h2 {
font-size: 20px; display: flex; align-items: center; gap: 8px;
}
#researchbee-app .card-header p {
font-size: 13px; color: var(--text-muted); margin-top: 4px;
}
#researchbee-app .card-body {
padding: 24px;
}
#researchbee-app .form-grid {
display: grid; gap: 16px;
}
#researchbee-app .form-2col {
grid-template-columns: 1fr 1fr;
}
#researchbee-app .form-3col {
grid-template-columns: 1fr 1fr 1fr;
}
@media (max-width:640px) {
#researchbee-app .form-2col,
#researchbee-app .form-3col {
grid-template-columns: 1fr;
}
}
#researchbee-app .form-group {
display: flex; flex-direction: column; gap: 6px;
}
#researchbee-app .form-full {
grid-column: 1 / -1;
}
#researchbee-app label {
font-size: 13px; font-weight: 500;
}
#researchbee-app label .req {
color: var(--danger);
}
#researchbee-app input,
#researchbee-app textarea,
#researchbee-app select {
padding: 10px 12px; border: 1.5px solid var(--border-strong);
border-radius: var(--radius-sm); font-size: 14px; color: var(--text);
background: white; font-family: "Open Sans", Arial, sans-serif;
transition: border-color .2s, box-shadow .2s; width: 100%;
}
#researchbee-app input:focus,
#researchbee-app textarea:focus,
#researchbee-app select:focus {
outline: none; border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(32,89,168,.1);
}
#researchbee-app textarea {
resize: vertical; min-height: 90px;
}
#researchbee-app .section-sep {
border-top: 1px solid var(--border); margin: 20px 0 16px; padding-top: 16px;
}
#researchbee-app .section-label {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; font-size: 16px; margin-bottom: 14px;
}
#researchbee-app .btn {
display: inline-flex; align-items: center; gap: 8px;
padding: 12px 22px; border-radius: var(--radius-sm); border: none;
font-size: 14px; font-weight: 500; cursor: pointer;
transition: all .2s; font-family: "Open Sans", Arial, sans-serif;
}
#researchbee-app .btn-primary {
background: var(--primary); color: white; width: 100%; justify-content: center; font-size: 15px;
}
#researchbee-app .btn-primary:hover:not(:disabled) {
background: var(--primary-dark); transform: translateY(-1px); box-shadow: var(--shadow);
}
#researchbee-app .btn-primary:disabled {
opacity: .6; cursor: not-allowed; transform: none;
}
#researchbee-app .btn-ghost {
background: transparent; color: var(--text-muted);
border: 1.5px solid var(--border-strong); font-size: 13px; padding: 7px 14px;
}
#researchbee-app .btn-ghost:hover {
border-color: var(--primary); color: var(--primary); background: var(--primary-xlight);
}
#researchbee-app .progress-box {
background: var(--primary-xlight); border: 1px solid var(--primary-light);
border-radius: var(--radius); padding: 16px 20px; margin: 20px 0; display: none;
}
#researchbee-app .progress-box.show {
display: block;
}
#researchbee-app .p-step {
display: flex; align-items: center; gap: 10px;
font-size: 13px; color: var(--text-muted); margin-bottom: 6px; transition: color .3s;
}
#researchbee-app .p-step:last-child {
margin-bottom: 0;
}
#researchbee-app .p-step.active {
color: var(--primary); font-weight: 500;
}
#researchbee-app .p-step.done {
color: var(--success);
}
#researchbee-app .p-dot {
width: 8px; height: 8px; border-radius: 50%;
background: var(--border-strong); flex-shrink: 0;
}
#researchbee-app .p-step.active .p-dot {
background: var(--primary); animation: blink 1s infinite;
}
#researchbee-app .p-step.done .p-dot {
background: var(--success);
}
@keyframes blink {
0%,100% {
opacity:1
}
50% {
opacity:.4
}
}
#researchbee-app .results-header {
display: flex; align-items: center; justify-content: space-between;
flex-wrap: wrap; gap: 10px; margin: 28px 0 18px;
}
#researchbee-app .results-title {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; font-size: 26px;
}
#researchbee-app .results-meta {
display: flex; align-items: center; gap: 10px;
}
#researchbee-app .count-chip {
background: var(--primary-light); color: var(--primary);
font-size: 12px; font-weight: 700; padding: 4px 12px;
border-radius: 0 ; font-family: ui-monospace, monospace;
}
#researchbee-app .understanding {
margin-bottom: 20px;
}
#researchbee-app .understanding .card-body {
display: flex; flex-direction: column; gap: 12px;
}
#researchbee-app .tag-row {
display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px;
}
#researchbee-app .badge {
display: inline-flex; align-items: center; gap: 3px;
padding: 3px 10px; border-radius: 0 ; font-size: 12px;
font-weight: 600; border: 1.5px solid;
font-family: ui-monospace, monospace;
}
#researchbee-app .b-primary {
background: var(--primary-light); color: var(--primary); border-color: #C9D8EE;
}
#researchbee-app .b-success {
background: var(--success-light); color: var(--success); border-color: #6ee7b7;
}
#researchbee-app .b-warning {
background: var(--warning-light); color: var(--warning); border-color: #fcd34d;
}
#researchbee-app .b-danger {
background: var(--danger-light); color: var(--danger); border-color: #fca5a5;
}
#researchbee-app .b-muted {
background: #f3f4f6; color: var(--text-muted); border-color: var(--border);
}
#researchbee-app .b-accent {
background: var(--accent-light); color: #92400e; border-color: #fcd34d;
}
#researchbee-app .b-q1 {
background: #dcfce7; color: #15803d; border-color: #86efac;
}
#researchbee-app .b-q2 {
background: #dbeafe; color: #1d4ed8; border-color: #93c5fd;
}
#researchbee-app .b-q3 {
background: #fef9c3; color: #a16207; border-color: #fde047;
}
#researchbee-app .b-q4 {
background: #fee2e2; color: #b91c1c; border-color: #fca5a5;
}
#researchbee-app .j-card {
margin-bottom: 20px;
}
#researchbee-app .j-header {
padding: 18px 24px; border-bottom: 1px solid var(--border);
background: #FFFFFF;
}
#researchbee-app .j-meta {
font-size: 12px; color: var(--text-muted); font-family: ui-monospace, monospace; margin-bottom: 5px;
}
#researchbee-app .j-title {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; font-size: 22px; margin-bottom: 10px;
}
#researchbee-app .badge-row {
display: flex; gap: 8px; flex-wrap: wrap;
}
#researchbee-app .j-body {
padding: 20px 24px; display: flex; flex-direction: column; gap: 18px;
}
#researchbee-app .detail-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: 14px;
}
@media (max-width:600px) {
#researchbee-app .detail-grid {
grid-template-columns: 1fr;
}
}
#researchbee-app .detail-item h5 {
font-size: 13px; font-weight: 600; margin-bottom: 3px; display: flex; align-items: center; gap: 5px;
}
#researchbee-app .detail-item p {
font-size: 13px; color: var(--text-muted);
}
#researchbee-app .rank-box {
border: 2px solid var(--border); border-radius: var(--radius-sm);
padding: 14px; background: var(--bg-subtle);
}
#researchbee-app .rank-box.confirmed {
border-color: #6ee7b7; background: #f0fdf4;
}
#researchbee-app .rank-box.derived {
border-color: #fcd34d; background: #fffbeb;
}
#researchbee-app .rank-box.unverified {
border-color: #fca5a5; background: #fff1f2;
}
#researchbee-app .rank-head {
display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; margin-bottom: 10px;
}
#researchbee-app .rank-head h5 {
font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 5px;
}
#researchbee-app .rank-grid {
display: grid; grid-template-columns: repeat(3,1fr); gap: 8px;
}
@media (max-width:480px) {
#researchbee-app .rank-grid {
grid-template-columns: 1fr 1fr;
}
}
#researchbee-app .rank-item dt {
font-size: 11px; color: var(--text-muted);
}
#researchbee-app .rank-item dd {
font-size: 13px; font-family: ui-monospace, monospace; font-weight: 600;
}
#researchbee-app .rank-note {
font-size: 12px; color: var(--text-muted); font-style: italic; margin-top: 8px;
}
#researchbee-app .rank-verify {
font-size: 12px; margin-top: 4px;
}
#researchbee-app .version-list {
display: flex; flex-direction: column; gap: 10px;
}
#researchbee-app .version-card {
border: 1.5px solid var(--border); border-radius: var(--radius-sm);
padding: 14px; background: white;
}
#researchbee-app .v-head {
display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;
}
#researchbee-app .v-title {
font-size: 13px; font-weight: 600;
}
#researchbee-app .v-allowed {
font-size: 13px; font-weight: 700;
}
#researchbee-app .v-yes {
color: var(--success);
}
#researchbee-app .v-no {
color: var(--danger);
}
#researchbee-app .v-unclear {
color: var(--warning);
}
#researchbee-app .v-conditional {
color: #b45309;
}
#researchbee-app .v-none {
color: var(--text-muted);
}
#researchbee-app .opf-options {
margin-top: 10px; border-top: 1px solid var(--border); padding-top: 9px;
}
#researchbee-app .opf-options > summary {
cursor: pointer; color: var(--primary); font-size: 12px; font-weight: 600;
}
#researchbee-app .opf-option-list {
list-style: none; display: flex; flex-direction: column; gap: 8px; margin-top: 9px;
}
#researchbee-app .opf-option-item {
background: var(--bg-subtle); border: 1px solid var(--border);
border-radius: 0 ; padding: 9px 11px; font-size: 12px;
}
#researchbee-app .opf-option-summary {
font-weight: 600; color: var(--text); margin-bottom: 4px;
}
#researchbee-app .opf-option-meta {
color: var(--text-muted); line-height: 1.5;
}
#researchbee-app .v-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: 5px 16px;
}
@media (max-width:480px) {
#researchbee-app .v-grid {
grid-template-columns: 1fr;
}
}
#researchbee-app .v-grid dt {
font-size: 11px; color: var(--text-muted);
}
#researchbee-app .v-grid dd {
font-size: 12px;
}
#researchbee-app .v-full {
grid-column: 1/-1;
}
#researchbee-app .policy-notes {
border-left: 4px solid #C9D8EE; background: var(--primary-xlight);
border-radius: 0 var(--radius-sm) var(--radius-sm) 0; padding: 12px 16px;
}
#researchbee-app .policy-notes > * + * {
margin-top: 6px;
}
#researchbee-app .policy-notes p {
font-size: 13px;
}
#researchbee-app .p-risk {
color: var(--danger); display: flex; align-items: flex-start; gap: 6px;
}
#researchbee-app .oa-metrics {
display: grid; grid-template-columns: repeat(4,1fr); gap: 8px;
background: #f8f9fc; border: 1px solid var(--border);
border-radius: var(--radius-sm); padding: 12px 16px;
}
@media (max-width:480px) {
#researchbee-app .oa-metrics {
grid-template-columns: 1fr 1fr;
}
}
#researchbee-app .oa-m dt {
font-size: 11px; color: var(--text-muted);
}
#researchbee-app .oa-m dd {
font-size: 14px; font-family: ui-monospace, monospace; font-weight: 600;
}
#researchbee-app .oa-src {
font-size: 11px; color: var(--text-light); grid-column: 1/-1; margin-top: 2px;
}
#researchbee-app .verify-row {
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
padding-top: 12px; border-top: 1px solid var(--border);
}
#researchbee-app .verify-lbl {
font-size: 12px; color: var(--text-muted); white-space: nowrap;
}
#researchbee-app .vlink {
font-size: 12px; color: var(--primary); text-decoration: none;
display: inline-flex; align-items: center; gap: 3px; font-weight: 500;
transition: opacity .15s;
}
#researchbee-app .vlink:hover {
opacity: .7;
}
#researchbee-app .vlink-scopus {
background: var(--primary-light); padding: 3px 10px;
border-radius: 0 ; font-weight: 600;
}
#researchbee-app .rec-card {
border-left: 4px solid var(--accent);
}
#researchbee-app .rec-card .card-header {
background: #fffbeb;
}
#researchbee-app .rec-grid {
display: grid; grid-template-columns: 1fr 1fr; gap: 10px 24px;
}
@media (max-width:580px) {
#researchbee-app .rec-grid {
grid-template-columns: 1fr;
}
}
#researchbee-app .rec-item dt {
font-size: 12px; color: var(--text-muted);
}
#researchbee-app .rec-item dd {
font-size: 14px; font-weight: 500;
}
#researchbee-app .checks-list {
list-style: disc; padding-left: 18px; display: flex; flex-direction: column; gap: 4px;
}
#researchbee-app .checks-list li {
font-size: 13px; color: var(--text-muted);
}
#researchbee-app .khazna-card {
border: 2px solid var(--primary); border-radius: var(--radius-lg); overflow: hidden; margin: 24px 0;
}
#researchbee-app .khazna-head {
background: #2059A8;
color: white; padding: 16px 20px; display: flex; align-items: center; gap: 10px;
}
#researchbee-app .khazna-head h3 {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; font-size: 18px;
}
#researchbee-app .khazna-body {
padding: 16px 20px; background: #FFFFFF;
}
#researchbee-app .khazna-body p {
font-size: 13px; color: var(--text-muted); margin-bottom: 10px;
}
#researchbee-app .khazna-tip {
background: var(--accent-light); border: 1px solid #fcd34d;
border-radius: var(--radius-sm); padding: 10px 14px;
font-size: 12px; color: #92400e; margin-bottom: 14px;
display: flex; align-items: flex-start; gap: 8px;
}
#researchbee-app .khazna-actions {
display: flex; gap: 8px; flex-wrap: wrap;
}
#researchbee-app .k-btn {
padding: 8px 16px; border-radius: var(--radius-sm); font-size: 13px;
font-weight: 500; text-decoration: none; display: inline-flex;
align-items: center; gap: 6px; transition: all .2s;
}
#researchbee-app .k-btn-fill {
background: var(--primary); color: white;
}
#researchbee-app .k-btn-fill:hover {
background: var(--primary-dark);
}
#researchbee-app .k-btn-outline {
border: 1.5px solid var(--primary); color: var(--primary); background: white;
}
#researchbee-app .k-btn-outline:hover {
background: var(--primary-xlight);
}
#researchbee-app .extended-wrap {
margin-top: 28px;
}
#researchbee-app .ext-toggle {
display: flex; align-items: center; justify-content: space-between;
padding: 14px 20px; background: white; border: 1.5px solid var(--primary-light);
border-radius: var(--radius); cursor: pointer; font-size: 14px; font-weight: 600;
color: var(--primary); transition: all .2s; width: 100%;
font-family: "Open Sans", Arial, sans-serif;
}
#researchbee-app .ext-toggle:hover {
background: var(--primary-xlight);
}
#researchbee-app .ext-arrow {
transition: transform .25s; font-size: 12px;
}
#researchbee-app .ext-toggle.open .ext-arrow {
transform: rotate(180deg);
}
#researchbee-app .ext-body {
display: none; margin-top: 6px;
}
#researchbee-app .ext-body.show {
display: block;
}
#researchbee-app .ext-table {
width: 100%; border-collapse: collapse; background: white; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; font-size: 13px;
}
#researchbee-app .ext-table th {
background: var(--bg-subtle); padding: 10px 14px; text-align: left;
font-size: 11px; font-weight: 700; color: var(--text-muted);
border-bottom: 1px solid var(--border);
font-family: ui-monospace, monospace; text-transform: uppercase; letter-spacing: .06em;
}
#researchbee-app .ext-table td {
padding: 10px 14px; border-bottom: 1px solid var(--border); vertical-align: middle;
}
#researchbee-app .ext-table tr:last-child td {
border-bottom: none;
}
#researchbee-app .ext-table tr:hover td {
background: #FFFFFF;
}
#researchbee-app .ext-links {
display: flex; gap: 6px; flex-wrap: wrap;
}
#researchbee-app .el {
font-size: 11px; padding: 3px 8px; border-radius: 0 ;
text-decoration: none; font-weight: 600; display: inline-flex;
align-items: center; gap: 3px; transition: opacity .15s;
}
#researchbee-app .el:hover {
opacity: .75;
}
#researchbee-app .el-scopus {
background: var(--primary-light); color: var(--primary);
}
#researchbee-app .el-sherpa {
background: var(--success-light); color: var(--success);
}
#researchbee-app .r-card {
margin-bottom: 16px;
}
#researchbee-app .r-card.is-khazna {
border: 2px solid var(--primary);
}
#researchbee-app .r-card.is-khazna .j-header {
background: #EBF1FA;
}
#researchbee-app .r-specs {
display: grid; grid-template-columns: 1fr 1fr; gap: 8px 20px;
}
@media (max-width:500px) {
#researchbee-app .r-specs {
grid-template-columns: 1fr;
}
}
#researchbee-app .r-specs dt {
font-size: 12px; color: var(--text-muted);
}
#researchbee-app .r-specs dd {
font-size: 13px; font-weight: 500;
}
#researchbee-app .actions-list {
list-style: none; display: flex; flex-direction: column; gap: 8px;
}
#researchbee-app .action-item {
display: flex; align-items: flex-start; gap: 10px;
font-size: 13px; padding: 10px 14px;
background: var(--bg-subtle); border-radius: var(--radius-sm); border: 1px solid var(--border);
}
#researchbee-app .a-num {
background: var(--primary); color: white; border-radius: 50%;
width: 20px; height: 20px; min-width: 20px; display: flex; align-items: center;
justify-content: center; font-size: 11px; font-weight: 700; margin-top: 1px;
}
#researchbee-app .global-note {
font-size: 12px; color: var(--text-muted); font-style: italic;
margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border);
}
#researchbee-app .help-card {
border: 1px solid var(--border); border-radius: var(--radius);
background: white; padding: 16px 20px; margin-top: 28px;
display: flex; align-items: center; justify-content: space-between;
flex-wrap: wrap; gap: 12px;
}
#researchbee-app .help-left {
display: flex; align-items: center; gap: 12px;
}
#researchbee-app .help-icon {
font-size: 26px;
}
#researchbee-app .help-text h4 {
font-size: 14px; font-weight: 600; margin-bottom: 2px;
}
#researchbee-app .help-text p {
font-size: 12px; color: var(--text-muted);
}
#researchbee-app .help-links {
display: flex; gap: 8px;
}
#researchbee-app .acc {
border: 1px solid var(--border); border-radius: var(--radius-sm); overflow: hidden; margin-top: 8px;
}
#researchbee-app .acc-btn {
width: 100%; background: var(--bg-subtle); padding: 10px 14px; border: none;
cursor: pointer; font-size: 13px; font-weight: 500;
display: flex; align-items: center; justify-content: space-between;
color: var(--text); font-family: "Open Sans", Arial, sans-serif; transition: background .2s;
}
#researchbee-app .acc-btn:hover {
background: var(--primary-xlight);
}
#researchbee-app .acc-body {
padding: 12px 14px; display: none; border-top: 1px solid var(--border);
}
#researchbee-app .acc-body.open {
display: block;
}
#researchbee-app .acc-body ul {
list-style: disc; padding-left: 18px; display: flex; flex-direction: column; gap: 4px;
}
#researchbee-app .acc-body li {
font-size: 13px; color: var(--text-muted);
}
#researchbee-app .site-footer {
border-top: 1px solid var(--border); padding: 20px;
margin-top: 40px; background: white;
}
#researchbee-app .footer-inner {
max-width: 1100px; margin: 0 auto; display: flex;
justify-content: space-between; flex-wrap: wrap;
gap: 8px; font-size: 12px; color: var(--text-muted);
}
#researchbee-app .footer-inner a {
color: var(--primary); text-decoration: none;
}
#researchbee-app .footer-inner a:hover {
text-decoration: underline;
}
#researchbee-app .hidden {
display: none !important;
}
#researchbee-app .mt-4 {
margin-top: 16px;
}
#researchbee-app .mt-6 {
margin-top: 24px;
}
#researchbee-app .divider {
border: none; border-top: 1px solid var(--border); margin: 18px 0;
}
#researchbee-app .space-y > * + * {
margin-top: 18px;
}
#researchbee-app .site-header {
background: #001B48;
}
#researchbee-app .brand-bee {
width: 38px; height: 38px; border-radius: 50%;
background: white; display: flex; align-items: center;
justify-content: center; font-size: 20px; flex-shrink: 0;
}
#researchbee-app .hero {
display: none;
}
#researchbee-app .lb-welcome {
background: #f0f2f5; padding: 24px 20px 20px;
display: flex; flex-direction: column; align-items: center; gap: 12px;
}
#researchbee-app .lb-mascot {
display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center;
}
#researchbee-app .lb-bee {
width: 72px; height: 72px; border-radius: 50%;
background: white; border: 3px solid #e5e7eb;
display: flex; align-items: center; justify-content: center;
font-size: 36px; box-shadow: 0 4px 16px rgba(0,0,0,.08);
}
#researchbee-app .lb-title {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; font-size: 24px; color: #001B48; font-weight: 400;
}
#researchbee-app .lb-sub {
font-size: 13px; color: #6b7280; max-width: 400px; line-height: 1.6;
}
#researchbee-app .lb-card {
background: white; border: 1px solid #e5e7eb;
border-radius: 0 ; width: 100%; max-width: 580px;
overflow: hidden; box-shadow: 0 2px 12px rgba(0,0,0,.06);
}
#researchbee-app .lb-card-head {
background: #001B48;
padding: 20px 22px;
}
#researchbee-app .lb-card-eyebrow {
font-size: 10px; font-family: ui-monospace, monospace;
color: rgba(255,255,255,.5); letter-spacing: .1em;
text-transform: uppercase; margin-bottom: 8px;
}
#researchbee-app .lb-card-title {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; font-size: 17px;
color: white; line-height: 1.4;
}
#researchbee-app .lb-card-title em {
font-style: italic; color: #a5b4fc;
}
#researchbee-app .lb-stats {
display: flex; margin-top: 16px;
border-top: 1px solid rgba(255,255,255,.1); padding-top: 14px;
}
#researchbee-app .lb-stat {
flex: 1; text-align: center;
}
#researchbee-app .lb-stat + .lb-stat {
border-left: 1px solid rgba(255,255,255,.1);
}
#researchbee-app .lb-stat-n {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; font-size: 20px; color: white; display: block; line-height: 1;
}
#researchbee-app .lb-stat-l {
font-size: 10px; color: rgba(255,255,255,.4); display: block; margin-top: 3px;
}
#researchbee-app .lb-stat-sep {
width: 0;
}
#researchbee-app .lb-features {
display: flex; flex-direction: column;
}
#researchbee-app .lb-feat {
display: flex; align-items: center; gap: 14px;
padding: 13px 20px; border-bottom: 1px solid #f3f4f6;
cursor: pointer; transition: background .15s;
}
#researchbee-app .lb-feat:last-child {
border-bottom: none;
}
#researchbee-app .lb-feat:hover {
background: #FFFFFF;
}
#researchbee-app .lb-feat-ic {
width: 38px; height: 38px; border-radius: 0 ;
display: flex; align-items: center; justify-content: center;
font-size: 18px; flex-shrink: 0;
}
#researchbee-app .lb-feat-txt {
flex: 1; min-width: 0;
}
#researchbee-app .lb-feat-title {
font-size: 13px; font-weight: 600; color: #111827; display: block; line-height: 1.3;
}
#researchbee-app .lb-feat-desc {
font-size: 11px; color: #9ca3af; display: block; margin-top: 2px; line-height: 1.5;
}
#researchbee-app .lb-feat-arr {
color: #d1d5db; font-size: 18px; flex-shrink: 0; margin-left: auto;
}
#researchbee-app .lb-feat:hover .lb-feat-arr {
color: #001B48;
}
#researchbee-app .lb-contact {
background: white; border: 1px solid #e5e7eb; border-radius: 0 ;
padding: 13px 18px; width: 100%; max-width: 580px;
display: flex; align-items: center; gap: 12px;
}
#researchbee-app .lb-contact-ic {
width: 34px; height: 34px; background: #e8ecf5;
border-radius: 0 ; display: flex; align-items: center;
justify-content: center; font-size: 16px; flex-shrink: 0;
}
#researchbee-app .lb-contact-txt {
flex: 1;
}
#researchbee-app .lb-contact-title {
font-size: 13px; font-weight: 600; color: #001B48; display: block;
}
#researchbee-app .lb-contact-sub {
font-size: 11px; color: #9ca3af; display: block; margin-top: 2px;
}
#researchbee-app .lb-contact-sub a {
color: #2059A8; text-decoration: none;
}
#researchbee-app .lb-contact-sub a:hover {
text-decoration: underline;
}
#researchbee-app .lb-contact-btn {
background: #001B48; color: white; border: none;
border-radius: 0 ; padding: 8px 16px; font-size: 12px;
font-weight: 500; cursor: pointer; text-decoration: none;
font-family: "Open Sans", Arial, sans-serif; white-space: nowrap;
transition: background .2s;
}
#researchbee-app .lb-contact-btn:hover {
background: #243560;
}
#researchbee-app .tab-btn.active {
color: #001B48; border-bottom-color: #001B48;
}
#researchbee-app .tab-btn:hover {
color: #001B48;
}
#researchbee-app .mode-selector {
display: flex; gap: 12px; margin-bottom: 20px; flex-wrap: wrap;
}
#researchbee-app .mode-btn {
flex: 1; min-width: 200px; display: flex; align-items: center; gap: 12px;
padding: 14px 18px; border: 2px solid var(--border);
border-radius: var(--radius); background: white; cursor: pointer;
transition: all .2s; font-family: "Open Sans", Arial, sans-serif; text-align: left;
}
#researchbee-app .mode-btn:hover {
border-color: var(--primary); background: var(--primary-xlight);
}
#researchbee-app .mode-btn.active {
border-color: var(--primary); background: var(--primary-xlight);
}
#researchbee-app .mode-icon {
font-size: 22px; flex-shrink: 0;
}
#researchbee-app .mode-text {
display: flex; flex-direction: column; gap: 2px;
}
#researchbee-app .mode-title {
font-size: 14px; font-weight: 600; color: var(--text);
}
#researchbee-app .mode-desc {
font-size: 12px; color: var(--text-muted);
}
#researchbee-app .mode-btn.active .mode-title {
color: var(--primary);
}
#researchbee-app .subj-banner {
background: var(--primary-xlight); border: 1px solid var(--primary-light);
border-radius: var(--radius-sm); padding: 10px 16px; font-size: 13px;
margin-bottom: 16px; display: flex; align-items: center; gap: 8px;
}
#researchbee-app .subj-banner-icon {
font-weight: 700; color: var(--primary); white-space: nowrap;
}
#researchbee-app .subj-notfound {
text-align: center; padding: 40px 20px; background: white;
border: 1px solid var(--border); border-radius: var(--radius-lg);
}
#researchbee-app .subj-notfound-icon {
width: 48px; height: 48px; border-radius: 50%; background: var(--danger-light);
color: var(--danger); font-size: 22px; font-weight: 700;
display: flex; align-items: center; justify-content: center; margin: 0 auto 12px;
}
#researchbee-app .subj-notfound h3 {
font-family: "PT Sans", "Open Sans", Arial, sans-serif; font-size: 18px; margin-bottom: 6px;
}
#researchbee-app .subj-notfound p {
font-size: 13px; color: var(--text-muted); margin-bottom: 16px;
}
#researchbee-app .subj-tip {
background: var(--accent-light); border: 1px solid #fcd34d;
border-radius: var(--radius-sm); padding: 12px 16px; font-size: 13px; color: #92400e;
}
#researchbee-app .copy-chip {
display: inline-flex; align-items: center; gap: 4px;
font-family: ui-monospace, monospace; font-size: 12px;
background: #f3f4f6; color: var(--text); padding: 3px 8px;
border-radius: 0 ; cursor: pointer; border: 1px solid var(--border);
transition: background .15s; user-select: none;
}
#researchbee-app .copy-chip:hover {
background: var(--primary-light); border-color: #C9D8EE;
}
#researchbee-app .copy-chip-sm {
font-size: 11px; padding: 2px 6px;
}
#researchbee-app .copy-icon {
font-size: 11px; opacity: .6;
}
#researchbee-app .verify-scopus-row {
margin-top: 6px; padding-top: 6px; border-top: none;
}
#researchbee-app .verify-scopus-hint {
font-size: 12px; color: var(--text-muted);
display: flex; align-items: center; gap: 6px;
}
#researchbee-app .brand-mascot {
width: 38px; height: 38px; border-radius: 50%;
object-fit: cover; flex-shrink: 0;
border: 2px solid rgba(255,255,255,0.3);
}
#researchbee-app .lb-mascot-img {
width: 150px; max-width: 100%; height: auto; border-radius: 0 ;
object-fit: contain;
border: 0;
box-shadow: none;
}
#researchbee-app .results-mascot-row {
display: flex; align-items: center; gap: 10px; margin-bottom: 16px;
}
#researchbee-app .results-mascot-img {
width: 44px; height: 44px; border-radius: 50%;
object-fit: contain; background: #fff; padding: 1px; border: 2px solid var(--primary-light);
flex-shrink: 0;
}
#researchbee-app .results-mascot-bubble {
background: var(--primary-xlight); border: 1px solid var(--primary-light);
border-radius: 0 ; padding: 8px 14px;
font-size: 13px; color: var(--primary); font-weight: 500;
}
#researchbee-app .lang-btn {
padding: 4px 12px; border-radius: 0 ; border: 1px solid rgba(255,255,255,.25);
background: transparent; color: rgba(255,255,255,.75); font-size: 12px;
cursor: pointer; transition: all .2s; font-family: ui-monospace, monospace;
font-weight: 600;
}
#researchbee-app .lang-btn.active {
background: white; color: var(--primary); border-color: white;
}
#researchbee-app .lang-btn:hover:not(.active) {
background: rgba(255,255,255,.15); color: white;
}
#researchbee-app .acc-arrow.open {
transform: rotate(180deg) !important;
}
#researchbee-app .subj-cl-form {
padding: 4px 0;
}
#researchbee-app .subj-cl-form .form-group label {
font-size: 12px;
}
#researchbee-app .subj-cl-form input,
#researchbee-app .subj-cl-form textarea {
font-size: 13px;
padding: 8px 10px;
}
#researchbee-app .tabs-bar {
background: white;
border-bottom: none !important;
box-shadow: 0 2px 12px rgba(0,0,0,.08) !important;
}
#researchbee-app .tabs-inner {
gap: 0;
padding: 0 8px;
}
#researchbee-app .tab-btn {
flex: 1;
flex-direction: row;
align-items: center;
gap: 10px;
padding: 12px 16px !important;
border-radius: 0 ;
border-bottom: 3px solid transparent;
margin-bottom: 0 !important;
}
#researchbee-app .tab-icon-wrap {
width: 36px; height: 36px; border-radius: 0 ;
display: flex; align-items: center; justify-content: center;
font-size: 18px; flex-shrink: 0; transition: all .2s;
}
#researchbee-app .tab-icon-journal {
background: #EBF1FA;
}
#researchbee-app .tab-icon-license {
background: #d1fae5;
}
#researchbee-app .tab-icon-data {
background: #fef3c7;
}
#researchbee-app .tab-label-wrap {
display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
}
#researchbee-app .tab-label-main {
font-size: 14px; font-weight: 600; color: var(--text);
line-height: 1.2;
}
#researchbee-app .tab-label-sub {
font-size: 11px; color: var(--text-muted); line-height: 1.2;
}
#researchbee-app .tab-btn.active .tab-label-main {
color: #001B48;
}
#researchbee-app .tab-btn.active .tab-label-sub {
color: #2059A8;
}
#researchbee-app .tab-btn.active {
border-bottom-color: #001B48 !important;
}
#researchbee-app .tab-btn.active .tab-icon-journal {
background: #001B48; color: white;
}
#researchbee-app .tab-btn.active .tab-icon-license {
background: #059669; color: white;
}
#researchbee-app .tab-btn.active .tab-icon-data {
background: #d97706; color: white;
}
#researchbee-app .tab-btn:hover .tab-label-main {
color: #001B48;
}
@media (max-width:600px) {
#researchbee-app .tab-label-sub {
display: none;
}
#researchbee-app .tab-btn {
padding: 10px 10px !important; gap: 6px;
}
}
#researchbee-app .mode-selector {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
margin-bottom: 24px;
}
@media (max-width:600px) {
#researchbee-app .mode-selector {
grid-template-columns: 1fr;
}
}
#researchbee-app .mode-btn {
display: flex;
align-items: flex-start;
gap: 14px;
padding: 18px 20px !important;
border: 2px solid var(--border) !important;
border-radius: var(--radius-lg) !important;
background: white !important;
text-align: left;
cursor: pointer;
transition: all .2s;
position: relative;
overflow: hidden;
}
#researchbee-app .mode-btn::before {
content: "";
position: absolute; inset: 0;
background: transparent;
pointer-events: none;
}
#researchbee-app .mode-btn:hover {
border-color: #2059A8 !important;
box-shadow: 0 4px 16px rgba(32,89,168,.12);
transform: translateY(-2px);
}
#researchbee-app .mode-btn.active {
border-color: #001B48 !important;
background: #F7F9FC !important;
box-shadow: 0 4px 20px rgba(26,39,68,.12);
}
#researchbee-app .mode-icon-wrap {
width: 48px; height: 48px; border-radius: 0 ;
display: flex; align-items: center; justify-content: center;
font-size: 24px; flex-shrink: 0; transition: all .2s;
}
#researchbee-app .mode-icon-subject {
background: #EBF1FA;
}
#researchbee-app .mode-icon-manuscript {
background: #fef3c7;
}
#researchbee-app .mode-btn.active .mode-icon-subject {
background: #001B48;
}
#researchbee-app .mode-btn.active .mode-icon-manuscript {
background: #d97706;
}
#researchbee-app .mode-text {
display: flex; flex-direction: column; gap: 4px; flex: 1;
}
#researchbee-app .mode-title {
font-size: 16px !important;
font-weight: 700 !important;
color: var(--text) !important;
font-family: "PT Sans", "Open Sans", Arial, sans-serif;
}
#researchbee-app .mode-btn.active .mode-title {
color: #001B48 !important;
}
#researchbee-app .mode-desc {
font-size: 12px !important;
color: var(--text-muted) !important;
line-height: 1.5;
}
#researchbee-app .mode-tag {
display: inline-flex; align-items: center;
font-size: 11px; font-family: ui-monospace, monospace;
color: #2059A8; background: #EBF1FA;
padding: 2px 8px; border-radius: 0 ;
margin-top: 4px; width: fit-content;
}
#researchbee-app .mode-btn.active .mode-tag {
background: #001B48; color: white;
}
#researchbee-app .ar-banner {
display: flex; align-items: flex-start; gap: 10px;
background: #fdf4e7;
border: 1.5px solid #fcd34d; border-radius: var(--radius);
padding: 14px 18px; margin-bottom: 20px;
font-size: 14px; color: #92400e; direction: rtl; text-align: right;
font-family: "Open Sans", Arial, sans-serif; line-height: 1.6;
}
#researchbee-app .ar-banner-icon {
font-size: 20px; flex-shrink: 0;
}
#researchbee-app .doi-primary {
background: #f0f9ff;
border: 1.5px solid #7dd3fc;
border-radius: 0 ;
padding: 14px 16px;
}
#researchbee-app .doi-primary label {
font-weight: 600;
}
#researchbee-app .doi-primary .recommended {
display: inline-block; margin-left: 8px; font-weight: 500;
font-size: 11px; color: #0369a1; background: #e0f2fe;
border-radius: 0 ; padding: 2px 9px; vertical-align: middle;
}
#researchbee-app .field-hint {
font-size: 11.5px; color: var(--text-muted);
margin-top: 6px; line-height: 1.45;
}
#researchbee-app .or-divider {
display: flex; align-items: center; gap: 12px;
font-size: 11.5px; color: var(--text-light);
text-transform: uppercase; letter-spacing: .06em;
margin: 4px 0 -4px;
}
#researchbee-app .or-divider::before,
#researchbee-app .or-divider::after {
content: ""; flex: 1; height: 1px; background: var(--border, #e2e8f0);
}
#researchbee-app .prov-badge {
display: inline-flex; align-items: center; gap: 5px;
font-size: 11.5px; font-weight: 600; border-radius: 0 ;
padding: 3px 11px; letter-spacing: .01em;
}
#researchbee-app .prov-verified {
background: #dcfce7; color: #166534; border: 1px solid #86efac;
}
#researchbee-app .prov-unverified {
background: #fef3c7; color: #92400e; border: 1px solid #fcd34d;
}
#researchbee-app .prov-api {
background: #e0f2fe; color: #075985; border: 1px solid #7dd3fc;
}
#researchbee-app .source-panel {
border-radius: 0 ; padding: 12px 14px; margin-top: 14px;
font-size: 12.5px; line-height: 1.5;
}
#researchbee-app .sp-verified {
background: #f0fdf4; border: 1px solid #bbf7d0;
}
#researchbee-app .sp-unverified {
background: #fffbeb; border: 1px solid #fde68a;
}
#researchbee-app .sp-api {
background: #f0f9ff; border: 1px solid #bae6fd;
}
#researchbee-app .sp-head {
display: flex; align-items: center; gap: 7px; margin-bottom: 6px; font-size: 13px;
}
#researchbee-app .sp-note {
margin: 0 0 6px; color: var(--text-muted);
}
#researchbee-app .sp-meta {
margin: 2px 0; font-size: 11.5px; color: var(--text-muted);
}
#researchbee-app .sp-links {
display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px;
}
#researchbee-app .sp-link {
font-size: 11px; padding: 3px 10px; border-radius: 0 ;
background: #fff; border: 1px solid var(--border, #e2e8f0);
color: var(--text-muted); text-decoration: none;
}
#researchbee-app .sp-link:hover {
border-color: #94a3b8; color: #0f172a;
}
#researchbee-app .sp-link-primary {
background: #0369a1; border-color: #0369a1; color: #fff;
}
#researchbee-app .sp-link-primary:hover {
background: #075985; color: #fff;
}
#researchbee-app .deposit-stmt {
background: #f8fafc; border: 1px solid #cbd5e1;
border-left: 4px solid #0369a1; border-radius: 0 ;
padding: 12px 14px; margin-top: 14px;
}
#researchbee-app .ds-head {
display: flex; justify-content: space-between; align-items: center;
font-size: 12.5px; font-weight: 600; margin-bottom: 7px;
}
#researchbee-app .ds-copy {
background: #0369a1; color: #fff; border: none; border-radius: 0 ;
font-size: 11px; padding: 4px 12px; cursor: pointer; font-family: inherit;
}
#researchbee-app .ds-copy:hover {
background: #075985;
}
#researchbee-app .ds-body {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 11.5px; line-height: 1.55; color: #1e293b;
background: #fff; border: 1px solid #e2e8f0; border-radius: 0 ;
padding: 9px 11px; margin: 0 0 7px; white-space: pre-wrap; word-break: break-word;
}
#researchbee-app .ds-note {
font-size: 11px; color: var(--text-muted); margin: 0; font-style: italic;
}
#researchbee-app .khazna-status {
display: flex; gap: 12px; align-items: flex-start;
border-radius: 0 ; padding: 13px 15px; margin-top: 16px;
font-size: 13px; line-height: 1.5;
}
#researchbee-app .khazna-status strong {
display: block; margin-bottom: 3px; font-size: 13.5px;
}
#researchbee-app .khazna-status p {
margin: 0; color: var(--text-muted); font-size: 12.5px;
}
#researchbee-app .ks-icon {
font-size: 20px; line-height: 1; flex-shrink: 0;
}
#researchbee-app .ks-open {
background: #f0fdf4; border: 1px solid #bbf7d0;
}
#researchbee-app .ks-embargo {
background: #fffbeb; border: 1px solid #fde68a;
}
#researchbee-app .ks-restricted {
background: #fef2f2; border: 1px solid #fecaca;
}
#researchbee-app .ks-gap {
background: #eff6ff; border: 1px solid #bfdbfe;
}
#researchbee-app .ks-absent {
background: #f8fafc; border: 1px solid #e2e8f0;
}
#researchbee-app .ks-unknown {
background: #f8fafc; border: 1px dashed #cbd5e1;
}
#researchbee-app .ks-meta {
font-size: 11.5px; margin-top: 4px !important;
}
#researchbee-app .ks-link {
display: inline-block; margin-top: 6px; font-size: 11.5px;
color: #0369a1; text-decoration: none; font-weight: 500;
}
#researchbee-app .ks-link:hover {
text-decoration: underline;
}
#researchbee-app .syp-card {
margin-top: 16px; border-radius: 0 ; padding: 16px 18px;
background: #eff6ff;
border: 1px solid #bfdbfe;
}
#researchbee-app .syp-body h4 {
margin: 0 0 5px; font-size: 15px; color: #0c4a6e;
}
#researchbee-app .syp-body p {
margin: 0 0 11px; font-size: 12.5px; color: var(--text-muted); line-height: 1.5;
}
#researchbee-app .syp-btn {
display: inline-block; background: #0369a1; color: #fff;
padding: 8px 18px; border-radius: 0 ; font-size: 13px;
font-weight: 600; text-decoration: none;
}
#researchbee-app .syp-btn:hover {
background: #075985; color: #fff;
}
@media (max-width: 640px) {
#researchbee-app .doi-primary {
padding: 12px;
}
#researchbee-app .ds-head {
flex-direction: column; align-items: flex-start; gap: 6px;
}
}
#researchbee-app .doi-submit {
margin-top: 12px; width: 100%; justify-content: center;
}
@media (min-width: 640px) {
#researchbee-app .doi-submit {
width: auto;
}
}
#researchbee-app .subj-grid {
display: grid; gap: 12px;
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
#researchbee-app .subj-card {
border: 1px solid var(--border, #e2e8f0); border-radius: 0 ;
padding: 12px 14px; background: #fff;
}
#researchbee-app .subj-head a {
font-size: 14.5px; font-weight: 600; color: #0369a1; text-decoration: none;
}
#researchbee-app .subj-head a:hover {
text-decoration: underline;
}
#researchbee-app .subj-scope {
font-size: 12px; color: var(--text-muted); margin: 5px 0 9px; line-height: 1.45;
}
#researchbee-app .subj-meta {
margin: 0; font-size: 11.5px;
}
#researchbee-app .subj-meta div {
display: flex; gap: 6px; margin-bottom: 3px;
}
#researchbee-app .subj-meta dt {
color: var(--text-light); min-width: 58px;
}
#researchbee-app .subj-meta dd {
margin: 0; color: #1e293b;
}
#researchbee-app .subj-verified {
font-size: 10.5px; color: var(--text-light); margin: 8px 0 0; font-style: italic;
}
#researchbee-app .subj-note {
font-size: 12px; color: var(--text-muted); margin: 12px 0 0;
padding: 9px 12px; background: #f8fafc; border-radius: 0 ;
border-left: 3px solid #0369a1;
}
#researchbee-app .footer-sources {
font-size: 11px; line-height: 1.6; color: var(--text-light, #94a3b8);
max-width: 900px; margin: 10px auto 0; text-align: center;
}
#researchbee-app .footer-sources a {
color: var(--text-muted, #64748b); text-decoration: underline;
}
#researchbee-app .footer-sources a:hover {
color: #0369a1;
}
#researchbee-app .footer-sources strong {
color: var(--text-muted, #64748b);
}
#researchbee-app #rb-chat-launcher {
position: fixed; bottom: 28px; right: 28px; z-index: 1000;
background: #001B48;
border: none; cursor: pointer;
border-radius: 0 ;
padding: 10px 18px 10px 14px;
display: flex; align-items: center; gap: 10px;
box-shadow: 0 4px 20px rgba(32,89,168,.45), 0 1px 4px rgba(0,0,0,.2);
transition: transform .2s, box-shadow .2s; outline: none;
min-width: 0;
}
#researchbee-app #rb-chat-launcher:hover {
transform: translateY(-2px);
box-shadow: 0 8px 28px rgba(32,89,168,.55);
}
#researchbee-app #rb-chat-launcher:active {
transform: translateY(0);
}
#researchbee-app .rb-launcher-icon {
width: 38px; height: 38px; border-radius: 50%;
background: rgba(255,255,255,.15);
border: 2px solid rgba(255,255,255,.3);
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
font-family: Georgia, "PT Sans", "Open Sans", Arial, sans-serif;
font-size: 22px; font-weight: 700;
color: #fff; line-height: 1;
transition: background .2s;
}
#researchbee-app #rb-chat-launcher:hover .rb-launcher-icon {
background: rgba(255,255,255,.25);
}
#researchbee-app .rb-chat-mascot-icon {
object-fit: contain; background: #fff !important; padding: 2px;
}
#researchbee-app .rb-launcher-label {
display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
}
#researchbee-app .rb-launcher-label-top {
font-family: "Open Sans", Arial, sans-serif;
font-size: 12px; font-weight: 700;
color: rgba(255,255,255,.7);
line-height: 1.2; letter-spacing: .01em;
text-transform: uppercase;
}
#researchbee-app .rb-launcher-label-main {
font-family: Georgia, "PT Sans", "Open Sans", Arial, sans-serif;
font-size: 14px; font-weight: 400;
color: #fff; line-height: 1.2; white-space: nowrap;
}
#researchbee-app #rb-chat-badge {
position: absolute; top: -4px; right: -4px;
width: 14px; height: 14px; background: #F59E0B;
border-radius: 50%; border: 2px solid #fff; display: none;
}
#researchbee-app #rb-chat-badge.visible {
display: block;
}
#researchbee-app #rb-chat-tooltip {
position: fixed; bottom: 108px; right: 28px; z-index: 999;
background: #001B48; color: #fff; font-family: "Open Sans", Arial, sans-serif;
font-size: 13px; padding: 8px 14px; border-radius: 0 ;
white-space: nowrap; box-shadow: 0 4px 16px rgba(0,0,0,.18);
pointer-events: none; opacity: 0; transform: translateY(6px);
transition: opacity .3s, transform .3s;
}
#researchbee-app #rb-chat-tooltip::after {
content: ""; position: absolute; bottom: -6px; right: 22px;
border-left: 6px solid transparent; border-right: 6px solid transparent;
border-top: 6px solid #001B48;
}
#researchbee-app #rb-chat-tooltip.show {
opacity: 1; transform: translateY(0);
}
#researchbee-app #rb-chat-panel {
position: fixed; bottom: 98px; right: 28px; z-index: 999;
width: 370px; max-height: 560px;
background: #fff; border-radius: 0 ;
box-shadow: 0 12px 48px rgba(26,39,68,.18), 0 2px 8px rgba(0,0,0,.08);
display: flex; flex-direction: column; overflow: hidden;
transform: scale(0.92) translateY(12px); transform-origin: bottom right;
opacity: 0; pointer-events: none;
transition: opacity .22s, transform .22s;
}
#researchbee-app #rb-chat-panel.open {
opacity: 1; transform: scale(1) translateY(0); pointer-events: all;
}
#researchbee-app .rb-chat-header {
background: #001B48;
padding: 14px 16px; display: flex; align-items: center; gap: 10px; flex-shrink: 0;
}
#researchbee-app .rb-chat-header img {
width: 32px; height: 32px; border-radius: 50%; border: 2px solid rgba(255,255,255,.25); object-fit: contain; background: #fff; padding: 1px; flex-shrink: 0;
}
#researchbee-app .rb-chat-header-text {
flex: 1; min-width: 0;
}
#researchbee-app .rb-chat-header-name {
font-family: Georgia,serif; font-size: 15px; color: #fff; display: block; line-height: 1.2;
}
#researchbee-app .rb-chat-header-sub {
font-family: "Open Sans", Arial, sans-serif; font-size: 11px; color: rgba(255,255,255,.6);
}
#researchbee-app .rb-chat-status {
width: 8px; height: 8px; background: #34D399; border-radius: 50%; box-shadow: 0 0 0 2px rgba(52,211,153,.3); flex-shrink: 0;
}
#researchbee-app .rb-chat-close {
background: none; border: none; color: rgba(255,255,255,.6); cursor: pointer; padding: 4px; border-radius: 0 ; font-size: 18px; line-height: 1; transition: color .15s; flex-shrink: 0;
}
#researchbee-app .rb-chat-close:hover {
color: #fff;
}
#researchbee-app .rb-chat-disclaimer {
background: #FEF9C3; border-bottom: 1px solid #FDE68A; padding: 6px 14px; font-family: "Open Sans", Arial, sans-serif; font-size: 11px; color: #92400E; display: flex; align-items: center; gap: 6px; flex-shrink: 0;
}
#researchbee-app #rb-chat-messages {
flex: 1; overflow-y: auto; padding: 14px 14px 6px; display: flex; flex-direction: column; gap: 10px; scroll-behavior: smooth;
}
#researchbee-app #rb-chat-messages::-webkit-scrollbar {
width: 4px;
}
#researchbee-app #rb-chat-messages::-webkit-scrollbar-thumb {
background: #e2e8f0; border-radius: 0 ;
}
#researchbee-app .rb-msg {
display: flex; flex-direction: column; max-width: 88%; animation: rb-in .18s ease;
}
@keyframes rb-in {
from {
opacity:0;transform:translateY(6px)
}
to {
opacity:1;transform:translateY(0)
}
}
#researchbee-app .rb-msg.user {
align-self: flex-end; align-items: flex-end;
}
#researchbee-app .rb-msg.assistant {
align-self: flex-start; align-items: flex-start;
}
#researchbee-app .rb-bubble {
padding: 9px 13px; border-radius: 0 ; font-family: "Open Sans", Arial, sans-serif; font-size: 13.5px; line-height: 1.55; word-break: break-word;
}
#researchbee-app .rb-msg.user .rb-bubble {
background: #2059A8; color: #fff; border-bottom-right-radius: 0;
}
#researchbee-app .rb-msg.assistant .rb-bubble {
background: #F1F5F9; color: #1e293b; border-bottom-left-radius: 0;
}
#researchbee-app .rb-msg.assistant .rb-bubble a {
color: #2059A8; text-decoration: underline;
}
#researchbee-app .rb-typing {
display: flex; align-items: center; gap: 4px; padding: 10px 14px; background: #F1F5F9; border-radius: 0 ; border-bottom-left-radius: 0; width: fit-content;
}
#researchbee-app .rb-typing span {
width: 7px; height: 7px; background: #94a3b8; border-radius: 50%; display: inline-block; animation: rb-bounce 1.2s infinite ease-in-out;
}
#researchbee-app .rb-typing span:nth-child(2) {
animation-delay:.15s
}
#researchbee-app .rb-typing span:nth-child(3) {
animation-delay:.30s
}
@keyframes rb-bounce {
0%,80%,100% {
transform:translateY(0)
}
40% {
transform:translateY(-5px)
}
}
#researchbee-app .rb-starters {
display: flex; flex-direction: column; gap: 6px; margin-top: 4px;
}
#researchbee-app .rb-starter-btn {
background: #fff; border: 1px solid #e2e8f0; border-radius: 0 ; padding: 8px 12px; font-family: "Open Sans", Arial, sans-serif; font-size: 12.5px; color: #2059A8; cursor: pointer; text-align: left; transition: background .15s, border-color .15s; line-height: 1.4;
}
#researchbee-app .rb-starter-btn:hover {
background: #EEF3FA; border-color: #2059A8;
}
#researchbee-app .rb-route-btn {
border: none; border-radius: 0 ; padding: 9px 14px; font-family: "Open Sans", Arial, sans-serif; font-size: 13px; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; gap: 7px; transition: opacity .15s; margin-top: 4px; color: white;
}
#researchbee-app .rb-route-btn:hover {
opacity: 0.88;
}
#researchbee-app .rb-chat-input-wrap {
padding: 10px 12px 12px; border-top: 1px solid #f1f5f9; display: flex; gap: 8px; align-items: flex-end; flex-shrink: 0; background: #fff;
}
#researchbee-app #rb-chat-input {
flex: 1; border: 1.5px solid #e2e8f0; border-radius: 0 ; padding: 9px 12px; font-family: "Open Sans", Arial, sans-serif; font-size: 13.5px; resize: none; outline: none; line-height: 1.45; max-height: 100px; overflow-y: auto; color: #1e293b; background: #f8fafc; transition: border-color .15s, background .15s;
}
#researchbee-app #rb-chat-input:focus {
border-color: #2059A8; background: #fff;
}
#researchbee-app #rb-chat-input::placeholder {
color: #94a3b8;
}
#researchbee-app #rb-chat-send {
width: 38px; height: 38px; border-radius: 0 ; background: #2059A8; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: opacity .15s, transform .1s;
}
#researchbee-app #rb-chat-send:hover {
opacity: .9;
}
#researchbee-app #rb-chat-send:active {
transform: scale(.93);
}
#researchbee-app #rb-chat-send:disabled {
opacity: .4; cursor: not-allowed;
}
#researchbee-app .rb-chat-footer {
padding: 5px 14px 8px; text-align: center; font-family: "Open Sans", Arial, sans-serif; font-size: 10.5px; color: #94a3b8; flex-shrink: 0;
}
#researchbee-app .rb-chat-footer a {
color: #94a3b8; text-decoration: none;
}
@media (max-width:480px) {
#researchbee-app #rb-chat-panel {
width:calc(100vw - 32px);right:16px;bottom:96px
}
#researchbee-app #rb-chat-launcher {
right:16px;bottom:16px;padding:8px 14px 8px 10px
}
#researchbee-app .rb-launcher-label-main {
font-size:13px
}
#researchbee-app #rb-chat-tooltip {
right:16px;bottom:120px
}
}
#researchbee-app .tabs-bar {
background: #e8ecf2 !important;
box-shadow: 0 2px 12px rgba(0,0,0,.1) !important;
border-bottom: none !important;
padding-bottom: 0 !important;
}
#researchbee-app .tabs-inner {
padding: 8px 10px 0 10px !important; gap: 6px !important; align-items: flex-end !important;
}
#researchbee-app .tab-btn {
border-bottom: 3px solid transparent !important;
border-radius: 0 !important;
margin: 0 !important; min-width: 0 !important;
transition: filter .18s, transform .15s, box-shadow .18s !important;
padding: 10px 14px !important;
outline: 2px solid transparent !important;
outline-offset: 0px !important;
}
#researchbee-app .tab-btn[data-tab="journals"] {
background: #001B48 !important;
}
#researchbee-app .tab-btn[data-tab="license"] {
background: #065f46 !important;
}
#researchbee-app .tab-btn[data-tab="data"] {
background: #92400e !important;
}
#researchbee-app .tab-btn:hover {
filter: brightness(1.12) !important; transform: translateY(-1px) !important;
}
#researchbee-app .tab-btn.active[data-tab="journals"] {
background: #001B48 !important;
border-bottom-color: #a5b4fc !important;
transform: translateY(-3px) !important;
box-shadow: 0 -3px 0 2px #a5b4fc, 0 -6px 16px rgba(99,102,241,.35) !important;
}
#researchbee-app .tab-btn.active[data-tab="license"] {
background: #065f46 !important;
border-bottom-color: #6ee7b7 !important;
transform: translateY(-3px) !important;
box-shadow: 0 -3px 0 2px #6ee7b7, 0 -6px 16px rgba(5,150,105,.35) !important;
}
#researchbee-app .tab-btn.active[data-tab="data"] {
background: #92400e !important;
border-bottom-color: #fcd34d !important;
transform: translateY(-3px) !important;
box-shadow: 0 -3px 0 2px #fcd34d, 0 -6px 16px rgba(217,119,6,.35) !important;
}
#researchbee-app .tab-label-main {
font-size: 13px !important; font-weight: 600 !important;
color: rgba(255,255,255,.82) !important;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#researchbee-app .tab-label-sub {
color: rgba(255,255,255,.5) !important; font-size: 10.5px !important;
}
#researchbee-app .tab-btn.active .tab-label-main {
color: #fff !important;
}
#researchbee-app .tab-btn.active .tab-label-sub {
color: rgba(255,255,255,.75) !important;
}
#researchbee-app .tab-btn:hover .tab-label-main {
color: #fff !important;
}
#researchbee-app .tab-icon-wrap {
background: rgba(255,255,255,.15) !important; color: rgba(255,255,255,.85) !important;
}
#researchbee-app .tab-btn.active .tab-icon-wrap {
background: rgba(255,255,255,.22) !important; color: #fff !important;
}
@media (max-width:600px) {
#researchbee-app .tabs-inner {
padding: 6px 6px 0 6px !important; gap: 4px !important;
}
#researchbee-app .tab-btn {
padding: 8px 6px !important; gap: 5px !important; flex: 1 !important; border-radius: 0 !important;
}
#researchbee-app .tab-btn:hover {
transform: translateY(0) !important;
}
#researchbee-app .tab-btn.active {
transform: translateY(-2px) !important;
}
#researchbee-app .tab-icon-wrap {
width: 24px !important; height: 24px !important; font-size: 12px !important; border-radius: 0 !important; flex-shrink: 0 !important;
}
#researchbee-app .tab-label-main {
font-size: 11px !important;
}
#researchbee-app .tab-label-sub {
display: none !important;
}
}
@media (max-width:360px) {
#researchbee-app .tabs-inner {
padding: 5px 3px 0 3px !important; gap: 3px !important;
}
#researchbee-app .tab-btn {
padding: 7px 3px !important; gap: 3px !important;
}
#researchbee-app .tab-label-main {
font-size: 10px !important;
}
#researchbee-app .tab-icon-wrap {
width: 20px !important; height: 20px !important; font-size: 10px !important;
}
}
#researchbee-app #rb-mobile-chat-bar {
display: none;
}
@media (max-width:600px) {
#researchbee-app #rb-chat-launcher {
display: none !important;
}
#researchbee-app #rb-chat-tooltip {
display: none !important;
}
#researchbee-app #rb-mobile-chat-bar {
display: flex !important;
position: sticky; top: 0; z-index: 95;
width: 100%;
background: #001B48;
align-items: center;
padding: 7px 14px; gap: 9px;
cursor: pointer; border: none;
box-shadow: 0 2px 8px rgba(0,0,0,.25);
font-family: "Open Sans", Arial, sans-serif;
}
#researchbee-app .rb-mobile-bar-icon {
width: 26px; height: 26px; border-radius: 50%;
background: rgba(255,255,255,.15);
border: 1.5px solid rgba(255,255,255,.35);
display: flex; align-items: center; justify-content: center;
font-family: Georgia, "PT Sans", "Open Sans", Arial, sans-serif;
font-size: 15px; font-weight: 700; color: #fff; flex-shrink: 0;
}
#researchbee-app .rb-mobile-bar-text {
display: flex; align-items: baseline; gap: 5px; flex: 1;
}
#researchbee-app .rb-mobile-bar-top {
font-size: 11px; font-weight: 700; color: rgba(255,255,255,.6); text-transform: uppercase; letter-spacing: .05em;
}
#researchbee-app .rb-mobile-bar-main {
font-size: 12px; font-weight: 500; color: #fff;
}
#researchbee-app .rb-mobile-bar-arrow {
font-size: 14px; color: rgba(255,255,255,.6); margin-left: auto; flex-shrink: 0;
}
#researchbee-app #rb-chat-panel {
bottom: auto !important; top: 0 !important;
right: 0 !important; left: 0 !important;
width: 100% !important; max-height: 78vh !important;
border-radius: 0 !important;
transform-origin: top center !important;
}
}
#researchbee-app #rb-mobile-chat-bar {
display: none;
}
@media (max-width:600px) {
#researchbee-app #rb-chat-launcher {
display: none !important;
}
#researchbee-app #rb-chat-tooltip {
display: none !important;
}
#researchbee-app #rb-mobile-chat-bar {
display: flex !important;
position: sticky;
top: 0;
z-index: 91; /* above tabs bar z-index:90 */
width: 100%;
background: #001B48;
align-items: center;
padding: 7px 14px;
gap: 9px;
cursor: pointer;
border: none;
box-shadow: 0 1px 6px rgba(0,0,0,.25);
font-family: "Open Sans", Arial, sans-serif;
}
#researchbee-app .rb-mobile-bar-icon {
width: 26px; height: 26px; border-radius: 50%;
background: rgba(255,255,255,.15);
border: 1.5px solid rgba(255,255,255,.3);
display: flex; align-items: center; justify-content: center;
font-family: Georgia, "PT Sans", "Open Sans", Arial, sans-serif;
font-size: 15px; font-weight: 700; color: #fff; flex-shrink: 0;
}
#researchbee-app .rb-mobile-bar-text {
display: flex; align-items: baseline; gap: 5px; flex: 1;
}
#researchbee-app .rb-mobile-bar-top {
font-size: 11px; font-weight: 700;
color: rgba(255,255,255,.6);
text-transform: uppercase; letter-spacing: .05em;
}
#researchbee-app .rb-mobile-bar-main {
font-size: 12px; font-weight: 500; color: #fff;
}
#researchbee-app .rb-mobile-bar-arrow {
font-size: 14px; color: rgba(255,255,255,.6);
margin-left: auto; flex-shrink: 0;
}
#researchbee-app #rb-chat-panel {
bottom: auto !important; top: 0 !important;
right: 0 !important; left: 0 !important;
width: 100% !important; max-height: 78vh !important;
border-radius: 0 !important;
transform-origin: top center !important;
}
}
#researchbee-app .deeper-analysis-strip {
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
padding: 10px 0 4px; border-top: 1px solid var(--border); margin-top: 4px;
}
#researchbee-app .deeper-analysis-label {
font-size: 12px; font-weight: 600; color: var(--text-muted); white-space: nowrap;
}
#researchbee-app .da-link {
display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px;
border-radius: 0 ; font-size: 11.5px; font-weight: 600; text-decoration: none;
transition: opacity .15s; font-family: "Open Sans", Arial, sans-serif;
}
#researchbee-app .da-link:hover {
opacity: .8;
}
#researchbee-app .da-scopus {
background: #EBF1FA; color: #174483;
}
#researchbee-app .da-wos {
background: #d1fae5; color: #065f46;
}
#researchbee-app .da-scival {
background: #fef3c7; color: #92400e;
}
#researchbee-app .da-library {
background: #f1f5f9; color: #475569;
}
#researchbee-app .subject-deeper-strip {
background: #f8fafc; border: 1px solid var(--border);
border-radius: 0 ; padding: 14px 16px; margin: 12px 0;
}
#researchbee-app .trending-papers-wrap {
margin: 16px 0;
}
#researchbee-app .rw-tab:focus {
outline: 2px solid #2059A8; outline-offset: 2px;
}
#researchbee-app .jf-guide-card {
display: flex; align-items: center; justify-content: space-between;
gap: 16px; flex-wrap: wrap;
background: #001B48;
border-radius: 0 ; padding: 18px 20px; margin: 16px 0;
box-shadow: 0 2px 12px rgba(26,39,68,.2);
}
#researchbee-app .jf-guide-left {
display: flex; align-items: flex-start; gap: 14px; flex: 1; min-width: 0;
}
#researchbee-app .jf-guide-icon {
font-size: 28px; flex-shrink: 0;
width: 48px; height: 48px; border-radius: 0 ;
background: rgba(255,255,255,.12);
display: flex; align-items: center; justify-content: center;
}
#researchbee-app .jf-guide-title {
font-family: Georgia, "PT Sans", "Open Sans", Arial, sans-serif;
font-size: 16px; font-weight: 400; color: #fff;
margin: 0 0 4px; line-height: 1.3;
}
#researchbee-app .jf-guide-desc {
font-family: "Open Sans", Arial, sans-serif;
font-size: 12.5px; color: rgba(255,255,255,.72);
margin: 0; line-height: 1.5;
}
#researchbee-app .jf-guide-btn {
display: inline-flex; align-items: center; gap: 6px;
background: #fff; color: #001B48;
font-family: "Open Sans", Arial, sans-serif;
font-size: 13px; font-weight: 700;
padding: 10px 20px; border-radius: 0 ;
text-decoration: none; white-space: nowrap; flex-shrink: 0;
transition: background .15s, transform .15s;
}
#researchbee-app .jf-guide-btn:hover {
background: #EBF1FA; transform: translateY(-1px);
}
#researchbee-app .sort-bar {
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
margin-bottom: 12px; padding: 8px 12px;
background: #f8fafc; border: 1px solid var(--border);
border-radius: 0 ;
}
#researchbee-app .sort-label {
font-size: 12px; font-weight: 600; color: var(--text-muted);
margin-right: 2px; white-space: nowrap;
}
#researchbee-app .sort-btn {
padding: 4px 12px; border-radius: 0 ; border: 1.5px solid #e2e8f0;
background: #fff; font-family: "Open Sans", Arial, sans-serif;
font-size: 12px; font-weight: 500; color: #64748b;
cursor: pointer; transition: all .15s; white-space: nowrap;
}
#researchbee-app .sort-btn:hover {
border-color: #2059A8; color: #2059A8; background: #F4F7FC;
}
#researchbee-app .sort-btn.active {
border-color: #2059A8; color: #2059A8; background: #EBF1FA; font-weight: 700;
}
#researchbee-app tr.q1-row {
background: #fafff5 !important;
}
#researchbee-app tr.q1-row td:first-child {
border-left: 3px solid #059669;
}
#researchbee-app .ku-apc-note {
background: #fefce8;
border: 1.5px solid #fde047;
border-radius: 0 ;
padding: 12px 14px;
margin-bottom: 12px;
font-family: "Open Sans", Arial, sans-serif;
font-size: 13px;
color: #854d0e;
line-height: 1.5;
}
#researchbee-app .ku-apc-note a {
color: #854d0e; font-weight: 600;
}
#researchbee-app .ku-apc-note a:hover {
text-decoration: underline;
}
@keyframes rb-blink {
0%,100% {
opacity:1
}
50% {
opacity:0
}
}
#researchbee-app .rb-cursor {
display: inline-block; animation: rb-blink .7s infinite; color: #2059A8; font-weight: 300;
}
#researchbee-app .altmetric-wrap {
display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 8px 0; border-top: 1px solid var(--border);
}
#researchbee-app .altmetric-label {
font-size: 11px; color: var(--text-muted);
}
#researchbee-app .altmetric-badge {
display: flex; align-items: center; gap: 8px;
}
#researchbee-app .altmetric-img {
width: 64px; height: 64px; object-fit: contain;
}
#researchbee-app .altmetric-score-pill {
background: #f97316; color: #fff; border-radius: 50%; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px; text-decoration: none;
}
#researchbee-app .altmetric-score-label {
font-size: 12px; color: var(--text-muted);
}
#researchbee-app .altmetric-src {
font-size: 10px; color: var(--text-light); text-decoration: none; margin-left: auto;
}
#researchbee-app .altmetric-src:hover {
color: var(--primary);
}
#researchbee-app .rw-loading {
font-size: 12px; color: var(--text-muted); padding: 8px 0; font-style: italic;
}
#researchbee-app .rw-list {
border-top: 1px solid var(--border); padding-top: 12px; display: flex; flex-direction: column; gap: 0;
}
#researchbee-app .rw-header {
font-size: 13px; font-weight: 600; margin-bottom: 10px;
}
#researchbee-app .rw-item {
padding: 9px 0; border-bottom: 1px solid #f1f5f9;
}
#researchbee-app .rw-item:last-of-type {
border-bottom: none;
}
#researchbee-app .rw-title {
font-size: 13px; font-weight: 500; color: var(--text); line-height: 1.4; margin-bottom: 3px;
}
#researchbee-app .rw-authors {
font-size: 11px; color: var(--text-muted); margin-bottom: 4px;
}
#researchbee-app .rw-meta {
display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 11px; color: var(--text-muted);
}
#researchbee-app .rw-src {
font-size: 10px; color: var(--text-light); margin-top: 8px;
}
#researchbee-app .rb-menu-wrap {
display: flex; flex-direction: column; gap: 7px; width: 100%; margin-top: 4px;
}
#researchbee-app .rb-menu-card {
display: flex; align-items: center; gap: 10px;
background: #fff; border: 1.5px solid #e2e8f0;
border-radius: 0 ; padding: 10px 12px;
cursor: pointer; text-align: left; width: 100%;
transition: border-color .15s, box-shadow .15s, transform .1s;
font-family: "Open Sans", Arial, sans-serif;
}
#researchbee-app .rb-menu-card:hover {
border-color: #2059A8;
box-shadow: 0 2px 10px rgba(32,89,168,.12);
transform: translateY(-1px);
}
#researchbee-app .rb-menu-card:active {
transform: translateY(0);
}
#researchbee-app .rb-menu-emoji {
font-size: 20px; flex-shrink: 0; width: 28px; text-align: center;
}
#researchbee-app .rb-menu-text {
flex: 1; display: flex; flex-direction: column; gap: 1px; min-width: 0;
}
#researchbee-app .rb-menu-title {
font-size: 12.5px; font-weight: 600; color: #1e293b; line-height: 1.3;
}
#researchbee-app .rb-menu-desc {
font-size: 11px; color: #94a3b8; line-height: 1.4;
}
#researchbee-app .rb-menu-arrow {
font-size: 16px; font-weight: 700; flex-shrink: 0; transition: transform .15s;
}
#researchbee-app .rb-menu-card:hover .rb-menu-arrow {
transform: translateX(3px);
}
#researchbee-app .rb-clear-btn {
align-self: flex-end; margin-top: 2px;
background: none; border: 1px solid #e2e8f0;
border-radius: 0 ; padding: 4px 12px;
font-family: "Open Sans", Arial, sans-serif; font-size: 11.5px;
color: #94a3b8; cursor: pointer; transition: border-color .15s, color .15s;
}
#researchbee-app .rb-clear-btn:hover {
border-color: #cbd5e1; color: #64748b;
}
/* LibGuides compatibility overrides */
#researchbee-app {
display: block;
position: relative;
width: 100%;
max-width: 100%;
min-width: 0;
min-height: 0;
overflow: visible;
color: var(--text, #111827);
background: var(--bg-subtle, #f9fafb);
font-family: system-ui, Arial, sans-serif;
font-size: 15px;
line-height: 1.6;
border: 1px solid #e5e7eb;
border-radius: 0 ;
}
#researchbee-app,
#researchbee-app *,
#researchbee-app *::before,
#researchbee-app *::after { box-sizing: border-box; }
#researchbee-app img { max-width: 100%; }
#researchbee-app button,
#researchbee-app input,
#researchbee-app textarea,
#researchbee-app select { font: inherit; }
#researchbee-app button { text-transform: none; letter-spacing: normal; }
#researchbee-app .rb-libguide-toolbar {
background: #001B48;
color: #fff;
border-radius: 0 ;
}
#researchbee-app .rb-libguide-toolbar .model-bar-inner {
max-width: 1100px;
padding: 8px 20px;
justify-content: flex-end;
}
#researchbee-app .rb-libguide-toolbar .model-label { color: rgba(255,255,255,.78); }
#researchbee-app .tabs-bar { position: relative !important; top: auto !important; z-index: 20; }
#researchbee-app .main-content { width: 100%; }
#researchbee-app .site-footer { margin-top: 0; border-radius: 0 ; }
#researchbee-app .footer-inner { display: block; }
#researchbee-app .footer-inner p + p { margin-top: 8px; }
#researchbee-app #rb-chat-launcher,
#researchbee-app #rb-chat-panel,
#researchbee-app #rb-chat-tooltip { z-index: 1055; }
#researchbee-app #rb-chat-launcher { z-index: 1056; }
#researchbee-app .rb-libguide-noscript {
margin: 16px 20px;
padding: 12px 14px;
border: 1px solid #f59e0b;
background: #fffbeb;
color: #92400e;
border-radius: 0 ;
}
@media (max-width: 767px) {
#researchbee-app .tab-label-wrap { min-width: 0; overflow: hidden; }
#researchbee-app .tab-label-main {
display: block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#researchbee-app { border-radius: 0 ; }
#researchbee-app .rb-libguide-toolbar { border-radius: 0 ; }
#researchbee-app .main-content { padding-left: 12px; padding-right: 12px; }
}
/* ==========================================================================
ResearchBee — Scopus / SCImago index display layer (journals.db)
Everything below is scoped to #researchbee-app like the rest of this sheet,
and uses the custom properties declared at the top of it rather than fresh
literals, so a future palette change carries through.
========================================================================== */
/* --- Diamond OA ----------------------------------------------------------
No article-processing charge for the author AND no subscription for the
reader. Distinct from "open access", which in practice usually means an APC
somebody has to find.
-------------------------------------------------------------------------- */
#researchbee-app .badge.b-diamond {
background: #ecfeff; color: #0e7490; border-color: #67e8f9;
}
/* --- per-field quartiles ------------------------------------------------- */
#researchbee-app .fq-block {
margin-top: 12px; padding: 12px 14px;
background: white; border: 1px solid var(--border);
border-radius: var(--radius-sm);
}
#researchbee-app .fq-label {
font-family: ui-monospace, monospace;
font-size: 11px; font-weight: 700; letter-spacing: .06em;
text-transform: uppercase; color: var(--text-muted); margin-bottom: 8px;
}
#researchbee-app .fq-chips {
display: flex; flex-wrap: wrap; gap: 8px;
}
#researchbee-app .fq-chip {
display: inline-flex; align-items: center; gap: 7px;
padding: 4px 12px 4px 5px;
background: var(--bg-subtle); border: 1px solid var(--border);
border-radius: 0 ; font-size: 12.5px; line-height: 1.5;
}
#researchbee-app .fq-chip .fq-field {
color: var(--text);
}
#researchbee-app .fq-note {
margin-top: 9px; font-size: 12px; line-height: 1.55;
color: var(--text-muted); font-style: italic;
}
#researchbee-app .subject-q-summary {
display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
}
#researchbee-app .subject-q-details {
margin-top: 6px; min-width: 190px;
}
#researchbee-app .subject-q-details summary {
cursor: pointer; color: var(--primary); font-size: 11px; font-weight: 600;
}
#researchbee-app .subject-q-list {
margin-top: 7px; display: flex; flex-direction: column; gap: 5px;
padding: 7px; background: var(--bg-subtle); border: 1px solid var(--border);
border-radius: 0 ;
}
#researchbee-app .subject-q-item {
display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px;
align-items: start;
}
#researchbee-app .subject-q-name {
font-size: 11px; line-height: 1.35; color: var(--text-muted);
}
/* --- indexation notice ---------------------------------------------------
Three visual weights for three genuinely different situations. Red is
reserved for the 967 titles Scopus discontinued; a renamed journal never
gets it, because styling a rename as a risk is worse than saying nothing.
Logical border properties so this survives if the app root is ever given
dir="rtl".
-------------------------------------------------------------------------- */
#researchbee-app .idx-notice {
margin: 0; padding: 13px 16px;
border: 1px solid transparent; border-inline-start: 4px solid;
border-radius: var(--radius-sm); font-size: 13.5px;
}
#researchbee-app .idx-head {
display: flex; align-items: center; gap: 8px;
font-weight: 600; font-size: 13.5px; margin-bottom: 6px;
}
#researchbee-app .idx-icon {
font-size: 16px; line-height: 1; flex-shrink: 0;
}
#researchbee-app .idx-msg {
font-size: 13px; line-height: 1.6;
}
#researchbee-app .idx-successor {
margin-top: 8px; font-size: 13px; line-height: 1.55;
}
#researchbee-app .idx-successor a {
margin-inline-start: 6px; white-space: nowrap; text-decoration: underline;
}
#researchbee-app .idx-notice.idx-danger {
background: var(--danger-light); border-inline-start-color: var(--danger); color: #7f1d1d;
}
#researchbee-app .idx-notice.idx-info {
background: var(--primary-xlight); border-inline-start-color: var(--primary); color: #001B48;
}
#researchbee-app .idx-notice.idx-muted {
background: var(--bg-subtle); border-inline-start-color: var(--border-strong); color: var(--text-muted);
}
#researchbee-app .idx-notice.idx-danger a { color: #7f1d1d; }
#researchbee-app .idx-notice.idx-info a { color: var(--primary-dark); }
#researchbee-app .idx-notice.idx-muted a { color: var(--text-muted); }
/* A discontinued title is still worth reading about, but it should not sit in
the shortlist looking like a recommendation. */
#researchbee-app .j-card[data-warn="1"] {
border-color: #fca5a5;
}
#researchbee-app .j-card[data-warn="1"] .j-header {
background: #fff7f7;
}
/* --- provenance ----------------------------------------------------------
"We could not check" has to look different from "we checked and it is
clean", the same distinction renderKhaznaStatus already makes.
-------------------------------------------------------------------------- */
#researchbee-app .rank-verify.rank-fallback {
color: var(--text-muted); line-height: 1.55; margin-top: 6px;
}
/* --- quick-match table ---------------------------------------------------
The extended list is where a discontinued title is most invisible: the
quartile column just renders "-" and nothing says why.
-------------------------------------------------------------------------- */
#researchbee-app .ext-flag {
display: inline-block; padding: 2px 8px; border-radius: 0 ;
font-family: ui-monospace, monospace;
font-size: 10.5px; font-weight: 600; white-space: nowrap;
border: 1px solid transparent; cursor: help;
}
#researchbee-app .ext-flag.idx-danger {
background: var(--danger-light); color: #991b1b; border-color: #fca5a5;
}
#researchbee-app .ext-flag.idx-info {
background: var(--primary-xlight); color: var(--primary); border-color: #C9D8EE;
}
#researchbee-app .ext-flag.idx-muted {
background: var(--bg-subtle); color: var(--text-muted); border-color: var(--border);
}
#researchbee-app .ext-diamond {
margin-inline-start: 6px; color: #047857; font-size: 11px; cursor: help;
}
#researchbee-app .ext-table tr[data-warn="1"] td {
background: #fff8f8;
}
#researchbee-app .ext-table tr[data-warn="1"]:hover td {
background: #fff1f1;
}
/* ResearchBee service introduction (v1.7) */
#researchbee-app #rb-service-intro-backdrop {
position: fixed;
inset: 0;
z-index: 1060;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
background: rgba(15, 23, 42, .42);
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: opacity .22s ease, visibility .22s ease;
}
#researchbee-app #rb-service-intro-backdrop.show {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
#researchbee-app .rb-service-intro {
width: min(620px, calc(100vw - 32px));
max-height: min(720px, calc(100vh - 40px));
overflow-y: auto;
position: relative;
background: #fff;
border: 1px solid rgba(255,255,255,.7);
border-radius: 0 ;
box-shadow: 0 24px 70px rgba(15,23,42,.28), 0 4px 16px rgba(15,23,42,.12);
transform: translateY(14px) scale(.975);
transition: transform .22s ease;
cursor: default;
}
#researchbee-app #rb-service-intro-backdrop.show .rb-service-intro {
transform: translateY(0) scale(1);
}
#researchbee-app .rb-service-intro-head {
padding: 24px 54px 21px 24px;
color: #fff;
background: #001B48;
border-radius: 0 ;
}
#researchbee-app .rb-service-intro-kicker {
display: inline-flex;
align-items: center;
gap: 7px;
margin-bottom: 7px;
font-family: ui-monospace, monospace;
font-size: 10.5px;
font-weight: 700;
letter-spacing: .08em;
text-transform: uppercase;
color: rgba(255,255,255,.68);
}
#researchbee-app .rb-service-intro-head h2 {
margin: 0 0 7px;
font-size: 25px;
color: #fff;
}
#researchbee-app .rb-service-intro-head p {
margin: 0;
max-width: 500px;
font-size: 13.5px;
line-height: 1.6;
color: rgba(255,255,255,.78);
}
#researchbee-app #rb-service-intro-close {
position: absolute;
top: 14px;
right: 14px;
z-index: 2;
width: 32px;
height: 32px;
border: 1px solid rgba(255,255,255,.25);
border-radius: 0 ;
background: rgba(255,255,255,.12);
color: #fff;
font-size: 21px;
line-height: 1;
cursor: pointer;
}
#researchbee-app #rb-service-intro-close:hover,
#researchbee-app #rb-service-intro-close:focus-visible {
background: rgba(255,255,255,.22);
outline: 2px solid rgba(255,255,255,.55);
outline-offset: 2px;
}
#researchbee-app .rb-service-intro-body {
padding: 18px 22px 20px;
}
#researchbee-app .rb-service-list {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
#researchbee-app .rb-service-item {
display: flex;
align-items: flex-start;
gap: 11px;
min-width: 0;
padding: 12px 13px;
border: 1px solid #e5e7eb;
border-radius: 0 ;
background: #f8fafc;
}
#researchbee-app .rb-service-item-icon {
width: 34px;
height: 34px;
flex: 0 0 34px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0 ;
background: #EBF1FA;
font-size: 17px;
}
#researchbee-app .rb-service-item:nth-child(2) .rb-service-item-icon { background: #d1fae5; }
#researchbee-app .rb-service-item:nth-child(3) .rb-service-item-icon { background: #fef3c7; }
#researchbee-app .rb-service-item:nth-child(4) .rb-service-item-icon { background: #f3e8ff; }
#researchbee-app .rb-service-item strong {
display: block;
margin-bottom: 2px;
font-size: 13px;
color: #1e293b;
}
#researchbee-app .rb-service-item span {
display: block;
font-size: 11.5px;
line-height: 1.45;
color: #64748b;
}
#researchbee-app .rb-service-intro-actions {
display: flex;
gap: 9px;
margin-top: 16px;
flex-wrap: wrap;
}
#researchbee-app .rb-service-intro-action {
flex: 1;
min-width: 180px;
border: 0;
border-radius: 0 ;
padding: 10px 15px;
font-family: "Open Sans", Arial, sans-serif;
font-size: 13px;
font-weight: 700;
cursor: pointer;
transition: transform .15s ease, box-shadow .15s ease, background .15s ease;
}
#researchbee-app .rb-service-intro-action:hover {
transform: translateY(-1px);
}
#researchbee-app #rb-service-intro-explore {
background: #EEF3FA;
color: #174483;
border: 1px solid #C9D8EE;
}
#researchbee-app #rb-service-intro-chat {
color: #fff;
background: #001B48;
box-shadow: 0 4px 12px rgba(32,89,168,.22);
}
#researchbee-app .rb-service-intro-hint {
margin: 12px 0 0;
text-align: center;
font-size: 10.5px;
color: #94a3b8;
}
@media (max-width: 600px) {
#researchbee-app #rb-service-intro-backdrop {
align-items: flex-end;
padding: 12px;
}
#researchbee-app .rb-service-intro {
width: 100%;
max-height: calc(100vh - 24px);
border-radius: 0 ;
}
#researchbee-app .rb-service-intro-head { padding: 20px 48px 17px 18px; }
#researchbee-app .rb-service-intro-head h2 { font-size: 22px; }
#researchbee-app .rb-service-intro-body { padding: 14px 16px 16px; }
#researchbee-app .rb-service-list { grid-template-columns: 1fr; gap: 8px; }
#researchbee-app .rb-service-item { padding: 10px 11px; }
#researchbee-app .rb-service-intro-action { min-width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
#researchbee-app #rb-service-intro-backdrop,
#researchbee-app .rb-service-intro { transition: none; }
}
/* ==========================================================================
ResearchBee v1.8 — unified verified journal discovery
========================================================================== */
#researchbee-app .rb-advanced {
margin-top: 18px; border: 1px solid var(--border); border-radius: 0 ;
background: #FFFFFF; overflow: hidden;
}
#researchbee-app .rb-advanced > summary {
cursor: pointer; padding: 12px 15px; font-size: 13px; font-weight: 700;
color: var(--primary-dark); list-style-position: inside; user-select: none;
}
#researchbee-app .rb-advanced[open] > summary { border-bottom: 1px solid var(--border); background: var(--primary-xlight); }
#researchbee-app .rb-advanced-body { padding: 16px; }
#researchbee-app .rb-check-field {
padding: 11px 13px; background: #fff; border: 1px solid var(--border); border-radius: 0 ;
}
#researchbee-app .rb-check-field label { display: flex; align-items: flex-start; gap: 9px; font-weight: 650; }
#researchbee-app .rb-check-field input[type="checkbox"],
#researchbee-app .rb-compare-checkbox { width: 17px; height: 17px; flex: 0 0 auto; margin-top: 2px; accent-color: var(--primary); }
#researchbee-app .rb-planning-only {
display: inline-flex; margin-left: 5px; padding: 1px 7px; border-radius: 0 ;
background: #f1f5f9; color: #64748b; font-size: 10px; font-weight: 600;
}
#researchbee-app .rb-criteria-card {
background: #fff; border: 1px solid var(--border); border-radius: 0 ;
padding: 15px 17px; margin: 0 0 18px; display: grid; gap: 12px;
}
#researchbee-app .rb-criteria-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
#researchbee-app .rb-criteria-card h4 { font-size: 13px; margin-bottom: 6px; color: var(--text); }
#researchbee-app .rb-criteria-list { margin: 0; padding-left: 19px; }
#researchbee-app .rb-criteria-list li { font-size: 12px; color: var(--text-muted); margin: 3px 0; }
#researchbee-app .rb-unverified-box { background: #fffbeb; border: 1px solid #fde68a; border-radius: 0 ; padding: 10px 12px; }
#researchbee-app .rb-verified-box { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 0 ; padding: 10px 12px; }
#researchbee-app .rb-journal-toolbar {
display: flex; align-items: center; justify-content: space-between; gap: 10px;
flex-wrap: wrap; margin: 10px 0 15px;
}
#researchbee-app .rb-policy-bulk,
#researchbee-app .rb-compare-open,
#researchbee-app .rb-export-compare {
border: 1.5px solid var(--primary); background: #fff; color: var(--primary-dark);
border-radius: 0 ; padding: 8px 13px; font: 600 12px "Open Sans", Arial, sans-serif;
cursor: pointer; transition: background .15s, transform .15s;
}
#researchbee-app .rb-policy-bulk:hover,
#researchbee-app .rb-compare-open:hover,
#researchbee-app .rb-export-compare:hover { background: var(--primary-xlight); transform: translateY(-1px); }
#researchbee-app .rb-policy-bulk:disabled,
#researchbee-app .rb-compare-open:disabled { opacity: .45; cursor: not-allowed; transform: none; }
#researchbee-app .rb-discovery-card { position: relative; }
#researchbee-app .rb-discovery-card .j-header { padding-right: 92px; }
#researchbee-app .rb-fit-score {
position: absolute; top: 15px; right: 18px; width: 58px; height: 58px;
border-radius: 50%; background: #fff; border: 3px solid var(--primary-light);
display: flex; flex-direction: column; align-items: center; justify-content: center;
box-shadow: var(--shadow-sm); color: var(--primary-dark); z-index: 2;
}
#researchbee-app .rb-fit-score strong { font: 700 18px ui-monospace,monospace; line-height: 1; }
#researchbee-app .rb-fit-score span { font-size: 9px; text-transform: uppercase; letter-spacing: .04em; margin-top: 2px; }
#researchbee-app .rb-card-select {
display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: var(--text-muted);
margin-top: 9px; width: fit-content; cursor: pointer;
}
#researchbee-app .rb-identity-row { display: flex; gap: 7px; flex-wrap: wrap; align-items: center; }
#researchbee-app .rb-id-badge {
display: inline-flex; align-items: center; gap: 4px; padding: 3px 9px; border-radius: 0 ;
background: #ecfdf5; border: 1px solid #a7f3d0; color: #047857; font-size: 10.5px; font-weight: 650;
}
#researchbee-app .rb-section-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 13px; }
#researchbee-app .rb-info-panel { border: 1px solid var(--border); border-radius: 0 ; padding: 12px 13px; background: #fff; }
#researchbee-app .rb-info-panel h5 { font-size: 12.5px; margin-bottom: 5px; }
#researchbee-app .rb-info-panel p { font-size: 12px; color: var(--text-muted); line-height: 1.55; }
#researchbee-app .rb-access-panel { background: #f8fafc; }
#researchbee-app .rb-ku-panel { background: #fffbeb; border-color: #fde68a; }
#researchbee-app .rb-policy-panel { background: #f0f9ff; border-color: #bae6fd; }
#researchbee-app .rb-policy-status { font-size: 12px; color: var(--text-muted); margin-bottom: 8px; }
#researchbee-app .rb-policy-actions { display: flex; flex-wrap: wrap; gap: 7px; }
#researchbee-app .rb-policy-check-btn {
border: none; border-radius: 0 ; padding: 7px 11px; background: #0369a1; color: #fff;
font: 650 11.5px "Open Sans", Arial, sans-serif; cursor: pointer;
}
#researchbee-app .rb-policy-check-btn:hover { background: #075985; }
#researchbee-app .rb-policy-check-btn:disabled { opacity: .55; cursor: wait; }
#researchbee-app .rb-policy-result { margin-top: 11px; }
#researchbee-app .rb-policy-result .version-card { padding: 10px; }
#researchbee-app .rb-policy-result .source-panel { margin-top: 10px; }
#researchbee-app .rb-policy-unknown { padding: 9px 11px; border-radius: 0 ; background: #fffbeb; border: 1px solid #fde68a; font-size: 12px; color: #92400e; }
#researchbee-app .rb-fit-breakdown { border: 1px solid var(--border); border-radius: 0 ; padding: 12px 13px; background: #FFFFFF; }
#researchbee-app .rb-fit-breakdown h5 { font-size: 12.5px; margin-bottom: 8px; }
#researchbee-app .rb-fit-component { display: grid; grid-template-columns: minmax(140px,1fr) 2fr auto; gap: 8px; align-items: center; margin: 6px 0; }
#researchbee-app .rb-fit-component-label { font-size: 11.5px; color: var(--text-muted); }
#researchbee-app .rb-fit-bar { height: 7px; background: #e5e7eb; border-radius: 0 ; overflow: hidden; }
#researchbee-app .rb-fit-bar > span { display: block; height: 100%; background: var(--primary); border-radius: 0 ; }
#researchbee-app .rb-fit-component-value { font: 600 10.5px ui-monospace,monospace; color: var(--text-muted); }
#researchbee-app .rb-evidence { border-top: 1px solid var(--border); padding-top: 12px; }
#researchbee-app .rb-evidence h5 { font-size: 12.5px; margin-bottom: 5px; }
#researchbee-app .rb-evidence-note { font-size: 11.5px; color: var(--text-muted); margin-bottom: 7px; }
#researchbee-app .rb-evidence-list { margin: 0; padding-left: 18px; }
#researchbee-app .rb-evidence-list li { margin: 5px 0; font-size: 12px; color: var(--text); }
#researchbee-app .rb-evidence-list a { color: var(--primary); text-decoration: none; }
#researchbee-app .rb-evidence-list a:hover { text-decoration: underline; }
#researchbee-app .rb-refine-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
#researchbee-app .rb-refine-btn { border: 1px solid var(--border-strong); background: #fff; color: var(--primary-dark); border-radius: 0 ; padding: 7px 11px; font-size: 11.5px; font-weight: 600; cursor: pointer; }
#researchbee-app .rb-refine-btn:hover { background: var(--primary-xlight); }
#researchbee-app .rb-extra-table .rb-extra-score { font: 700 12px ui-monospace,monospace; color: var(--primary-dark); }
#researchbee-app .rb-extra-actions { display: flex; flex-wrap: wrap; gap: 5px; }
#researchbee-app .rb-extra-policy { border: 1px solid #bae6fd; background: #f0f9ff; color: #075985; border-radius: 0 ; padding: 4px 7px; font-size: 10.5px; font-weight: 650; cursor: pointer; }
#researchbee-app .rb-comparison-panel { margin-top: 20px; border: 2px solid var(--primary-light); border-radius: 0 ; overflow: hidden; background: #fff; }
#researchbee-app .rb-comparison-head { display: flex; justify-content: space-between; gap: 10px; align-items: center; flex-wrap: wrap; padding: 14px 16px; background: var(--primary-xlight); }
#researchbee-app .rb-comparison-head h3 { font-size: 18px; }
#researchbee-app .rb-comparison-scroll { overflow-x: auto; }
#researchbee-app .rb-comparison-table { width: 100%; border-collapse: collapse; min-width: 700px; font-size: 12px; }
#researchbee-app .rb-comparison-table th,
#researchbee-app .rb-comparison-table td { border: 1px solid var(--border); padding: 9px 11px; text-align: left; vertical-align: top; }
#researchbee-app .rb-comparison-table th { background: #f8fafc; font-size: 11px; color: var(--text-muted); }
#researchbee-app .rb-comparison-table td:first-child { font-weight: 700; width: 150px; background: #FFFFFF; }
#researchbee-app .rb-comparison-empty { padding: 18px; font-size: 13px; color: var(--text-muted); }
#researchbee-app .rb-shortlist-count { font: 650 11.5px "Open Sans", Arial, sans-serif; color: var(--text-muted); }
#researchbee-app .rb-no-results { padding: 28px; text-align: center; background: #fff; border: 1px solid var(--border); border-radius: 0 ; }
#researchbee-app .rb-no-results h3 { font-size: 18px; margin-bottom: 7px; }
#researchbee-app .rb-no-results p { font-size: 13px; color: var(--text-muted); }
#researchbee-app .rb-subject-map-note {
margin-top: 10px; padding: 11px 13px; border-radius: 0 ;
background: #eff6ff; border: 1px solid #bfdbfe; border-left: 4px solid var(--primary);
color: #1e3a8a; font-size: 12.5px; line-height: 1.55;
}
#researchbee-app .rb-subject-map-note.spelling {
background: #f0fdf4; border-color: #bbf7d0; border-left-color: var(--success); color: #166534;
}
#researchbee-app .rb-subject-map-note.nearest {
background: #fffbeb; border-color: #fde68a; border-left-color: var(--warning); color: #78350f;
}
#researchbee-app .rb-re3data { margin: 22px 0; border: 1px solid var(--border); background: #fff; }
#researchbee-app .rb-re3data > summary {
cursor: pointer; padding: 14px 18px; font-weight: 700; font-size: 15px; color: var(--text);
background: var(--primary-xlight); list-style-position: inside;
}
#researchbee-app .rb-re3data > summary:focus-visible { outline: 3px solid var(--primary); outline-offset: 2px; }
#researchbee-app .rb-re3data-tag {
display: inline-block; margin-left: 8px; padding: 2px 8px; font-size: 11px; font-weight: 600;
background: #fffbeb; color: #78350f; border: 1px solid #fde68a; vertical-align: middle;
}
#researchbee-app .rb-re3data-body { padding: 14px 18px 18px; }
#researchbee-app .rb-re3data-intro { font-size: 13px; color: var(--text-muted); margin-bottom: 12px; }
#researchbee-app .rb-re3data-item { border-top: 1px solid var(--border); padding: 14px 0; }
#researchbee-app .rb-re3data-item:first-of-type { border-top: 0; padding-top: 4px; }
#researchbee-app .rb-re3data-item h4 { font-size: 16px; margin-bottom: 4px; overflow-wrap: anywhere; }
#researchbee-app .rb-re3data-item p { font-size: 13px; }
#researchbee-app .rb-re3data-item .r-specs { margin-top: 8px; }
#researchbee-app .rb-re3data-item .checks-list { margin-top: 10px; }
#researchbee-app .rb-re3data-item .verify-row { margin-top: 8px; }
#researchbee-app .rb-re3data-note { font-size: 13px; padding: 12px 16px; margin: 18px 0; }
#researchbee-app .rb-subject-alternatives { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 10px; align-items: center; }
#researchbee-app .rb-subject-alternatives-label { font-size: 11.5px; color: var(--text-muted); font-weight: 650; }
#researchbee-app .rb-version-badge {
display: inline-flex; padding: 2px 7px; border-radius: 0 ; margin-left: 5px;
background: #EEF3FA; color: #2059A8; border: 1px solid #C9D8EE;
font: 600 10px ui-monospace, monospace; vertical-align: middle;
}
@media (max-width: 700px) {
#researchbee-app .rb-criteria-columns,
#researchbee-app .rb-section-grid { grid-template-columns: 1fr; }
#researchbee-app .rb-discovery-card .j-header { padding-right: 78px; }
#researchbee-app .rb-fit-score { right: 12px; width: 52px; height: 52px; }
#researchbee-app .rb-fit-component { grid-template-columns: 1fr auto; }
#researchbee-app .rb-fit-bar { grid-column: 1 / -1; }
}
/* v1.8.2: keep closed controls out of keyboard navigation and preserve focus. */
#researchbee-app [hidden] { display: none !important; }
#researchbee-app button:focus-visible, #researchbee-app a:focus-visible,
#researchbee-app summary:focus-visible, #researchbee-app input:focus-visible,
#researchbee-app textarea:focus-visible, #researchbee-app select:focus-visible {
outline: 3px solid #2059A8 !important; outline-offset: 3px !important;
}
#researchbee-app .rb-data-notice { margin: 0 0 18px; padding: 12px 15px; border: 1px solid #cbd5e1; border-radius: 0 ; color: #334155; background: #f8fafc; font-size: 12px; line-height: 1.6; }
#researchbee-app .rb-cover-letter-notice { color: #475569; font-size: 12px; line-height: 1.6; }
#researchbee-app .rb-character-count { display: block; margin-top: 4px; font-size: 11px; color: #64748b; }
#researchbee-app .rb-extra-policy-row td { padding: 8px 12px; }
#researchbee-app .rb-extra-policy-row summary { cursor: pointer; font-weight: 600; font-size: 12px; }
#researchbee-app[dir="rtl"] .tab-label-wrap, #researchbee-app[dir="rtl"] .mode-text,
#researchbee-app[dir="rtl"] .detail-item, #researchbee-app[dir="rtl"] .form-group { text-align: start; }
#researchbee-app[dir="rtl"] input[type="text"], #researchbee-app[dir="rtl"] textarea { text-align: start; }
#researchbee-app #l-doi, #researchbee-app #l-issn { direction: ltr; unicode-bidi: isolate; text-align: left; }
@media (prefers-reduced-motion: reduce) {
#researchbee-app *, #researchbee-app *::before, #researchbee-app *::after { scroll-behavior: auto !important; animation: none !important; transition: none !important; }
}
/* v1.8.3: reserve image space and keep the introduction user initiated. */
#researchbee-app .lb-mascot-img { width: 150px; height: 125px; object-fit: contain; }
#researchbee-app img[data-rb-mascot], #researchbee-app .results-mascot-img { object-fit: contain; }
#researchbee-app .rb-about-btn { margin-inline-start: auto; border: 1px solid #cbd5e1; border-radius: 0 ; padding: 7px 11px; background: #fff; color: #334155; font: 600 12px "Open Sans", Arial, sans-serif; cursor: pointer; }
#researchbee-app .rb-about-btn:hover { background: #EEF3FA; }
/* v1.8.4: always-visible publication support banner, scoped for LibGuides. */
#researchbee-app .rb-purpose {
background: #fff; border-top: 3px solid #2059A8;
color: #001B48; text-align: start;
}
#researchbee-app .rb-purpose-inner {
max-width: 1100px; margin-inline: auto; padding: 28px 24px 26px;
display: grid; grid-template-columns: 144px minmax(0, 1fr);
column-gap: 28px; align-items: center;
}
#researchbee-app .rb-purpose-mascot {
grid-column: 1; grid-row: 1 / 3; display: flex; justify-content: center;
}
#researchbee-app .rb-purpose-image {
display: block; width: 144px; height: 144px; object-fit: contain;
}
#researchbee-app .rb-purpose-heading { grid-column: 2; min-width: 0; }
#researchbee-app .rb-purpose-kicker {
color: #5E6772; font-size: 12px; line-height: 1.5; font-weight: 700;
letter-spacing: .035em; margin-bottom: 6px;
}
#researchbee-app .rb-purpose h1 {
font-family: "Open Sans", Arial, sans-serif; font-size: clamp(25px, 3vw, 32px);
font-weight: 750; line-height: 1.2; letter-spacing: -.025em; color: #001B48;
}
#researchbee-app .rb-purpose-tagline {
margin-top: 7px; color: #526074; font-size: 16px; line-height: 1.5;
}
#researchbee-app .rb-purpose-services {
grid-column: 2; list-style: none; display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px;
margin: 22px 0 0; padding: 0;
}
#researchbee-app .rb-purpose-service { min-width: 0; }
#researchbee-app .rb-purpose-service-title { display: flex; align-items: flex-start; gap: 9px; }
#researchbee-app .rb-purpose-number {
display: inline-flex; flex: 0 0 26px; align-items: center; justify-content: center;
width: 26px; height: 26px; border-radius: 50%; background: #EBF1FA;
color: #2059A8; font-size: 13px; font-weight: 750; line-height: 1;
}
#researchbee-app .rb-purpose h2 {
font-family: "Open Sans", Arial, sans-serif; font-size: 17px; font-weight: 700;
line-height: 1.4; color: #001B48;
}
#researchbee-app .rb-purpose-service p {
margin-top: 8px; color: #526074; font-size: 15px; line-height: 1.55;
}
#researchbee-app .rb-purpose-search { background: #fffbf1; border-top: 1px solid #efdfb6; }
#researchbee-app .rb-purpose-search-inner {
max-width: 1100px; margin-inline: auto; padding: 15px 24px;
display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
#researchbee-app .rb-purpose-search-copy { min-width: 0; }
#researchbee-app .rb-purpose-search-copy strong {
display: block; font-size: 17px; line-height: 1.4; color: #001B48;
}
#researchbee-app .rb-purpose-search-copy p {
margin-top: 3px; font-size: 15px; line-height: 1.5; color: #4b5563;
}
#researchbee-app .rb-purpose-links { display: flex; flex: 0 0 auto; flex-wrap: wrap; gap: 8px; }
#researchbee-app .rb-purpose-link {
display: inline-flex; align-items: center; justify-content: center; min-height: 44px;
padding: 9px 15px; border: 1px solid #c7ceda; border-radius: 0 ;
background: #fff; color: #001B48; font: 650 15px/1.4 "Open Sans", Arial, sans-serif;
text-decoration: none; white-space: nowrap;
}
#researchbee-app .rb-purpose-link:hover { background: #001B48; border-color: #001B48; color: #fff; }
#researchbee-app .rb-purpose-link:focus-visible { outline: 3px solid #2059A8; outline-offset: 3px; }
#researchbee-app[dir="rtl"] .rb-purpose-kicker,
#researchbee-app[dir="rtl"] .rb-purpose h1 { letter-spacing: normal; }
@media (max-width: 900px) {
#researchbee-app .rb-purpose-inner { grid-template-columns: 112px minmax(0, 1fr); gap: 0 20px; }
#researchbee-app .rb-purpose-mascot { grid-row: 1; }
#researchbee-app .rb-purpose-image { width: 112px; height: 112px; }
#researchbee-app .rb-purpose-services { grid-column: 1 / -1; }
#researchbee-app .rb-purpose-search-inner { flex-wrap: wrap; }
}
@media (max-width: 600px) {
#researchbee-app .rb-purpose-inner { grid-template-columns: 70px minmax(0, 1fr); padding: 20px 16px; column-gap: 13px; }
#researchbee-app .rb-purpose-image { width: 70px; height: 78px; }
#researchbee-app .rb-purpose-kicker { font-size: 11px; margin-bottom: 5px; }
#researchbee-app .rb-purpose h1 { font-size: 24px; line-height: 1.25; }
#researchbee-app .rb-purpose-tagline { font-size: 15px; }
#researchbee-app .rb-purpose-services { grid-template-columns: 1fr; gap: 13px; margin-top: 20px; }
#researchbee-app .rb-purpose-service p { margin-top: 3px; padding-inline-start: 35px; }
#researchbee-app .rb-purpose-service + .rb-purpose-service { border-top: 1px solid #edf0f4; padding-top: 13px; }
#researchbee-app .rb-purpose-search-inner { padding: 15px 16px; gap: 12px; }
#researchbee-app .rb-purpose-links { width: 100%; }
#researchbee-app .rb-purpose-link { flex: 1; }
}
/* v1.9.0: a quiet home screen and one task at a time. */
#researchbee-app .rb-workflow-header {
max-width: 1100px; margin: 0 auto; padding: 26px 20px 14px;
display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
#researchbee-app .rb-workflow-header h2 {
font: 700 22px/1.35 "Open Sans", Arial, sans-serif; color: #001B48;
}
#researchbee-app .rb-clear-all,
#researchbee-app .rb-back-options {
min-height: 44px; border: 1px solid #cbd5e1; border-radius: 0 ;
background: #fff; color: #334155; padding: 9px 14px;
font: 600 14px/1.45 "Open Sans", Arial, sans-serif; cursor: pointer;
}
#researchbee-app .rb-clear-all:hover,
#researchbee-app .rb-back-options:hover { background: #edf2f8; border-color: #94a3b8; }
#researchbee-app .tabs-bar {
background: transparent !important; box-shadow: none !important;
}
#researchbee-app .tabs-bar .tabs-inner {
display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
padding: 0 20px !important; gap: 12px !important; align-items: stretch !important;
}
#researchbee-app .tabs-bar .tab-btn {
--rb-tab-colour: #001B48;
border: 1px solid #d6dce5 !important; border-radius: 0 !important;
background: #fff !important; box-shadow: none !important;
padding: 17px 16px !important; gap: 12px !important;
transform: none !important; filter: none !important;
text-align: start; transition: background .15s, border-color .15s !important;
}
#researchbee-app .tabs-bar .tab-btn[data-tab="license"] { --rb-tab-colour: #065f46; }
#researchbee-app .tabs-bar .tab-btn[data-tab="data"] { --rb-tab-colour: #92400e; }
#researchbee-app .tabs-bar .tab-btn:hover { background: #f2f5fa !important; border-color: #94a3b8 !important; }
#researchbee-app .tabs-bar .tab-btn.active {
background: var(--rb-tab-colour) !important; border-color: var(--rb-tab-colour) !important;
box-shadow: none !important; transform: none !important;
}
#researchbee-app .rb-function-number {
display: inline-flex; align-items: center; justify-content: center;
flex: 0 0 34px; width: 34px; height: 34px; border-radius: 50%;
background: #edf1f7; color: #001B48; font: 750 17px/1 "Open Sans", Arial, sans-serif;
}
#researchbee-app .tabs-bar .tab-btn.active .rb-function-number { background: #fff; color: var(--rb-tab-colour); }
#researchbee-app .tabs-bar .tab-label-wrap { overflow: visible; }
#researchbee-app .tabs-bar .tab-label-main {
white-space: normal !important; overflow: visible !important;
color: #001B48 !important; font-size: 17px !important; font-weight: 700 !important; line-height: 1.35;
}
#researchbee-app .tabs-bar .tab-label-sub { display: block !important; font-size: 12px !important; color: #526074 !important; line-height: 1.5; margin-top: 3px; }
#researchbee-app .tabs-bar .tab-btn.active .tab-label-main { color: #fff !important; }
#researchbee-app .tabs-bar .tab-btn.active .tab-label-sub { color: #e5edf7 !important; }
#researchbee-app .tabs-bar .tab-btn:focus-visible { outline: 3px solid #2059A8 !important; outline-offset: 3px !important; }
#researchbee-app .main-content { padding-top: 22px; }
#researchbee-app #rb-home-view { color: #526074; font-size: 16px; padding: 0 0 12px; }
#researchbee-app .rb-journal-choices { padding: 8px 0 12px; }
#researchbee-app .rb-journal-choices h2 {
color: #001B48; font: 750 clamp(25px, 3vw, 32px)/1.25 "Open Sans", Arial, sans-serif;
letter-spacing: -.02em; margin-bottom: 9px;
}
#researchbee-app .rb-choice-intro { font-size: 16px; color: #526074; line-height: 1.6; }
#researchbee-app .rb-journal-choices .mode-selector { margin: 24px 0 0; gap: 18px; }
#researchbee-app .rb-journal-choices :is(.mode-btn, .rb-choice-btn) {
display: flex; flex-direction: row; align-items: flex-start; gap: 14px;
padding: 24px !important; background: #fff !important; border: 1px solid #d6dce5 !important;
border-radius: 0 !important; box-shadow: none !important; transform: none !important;
min-width: 0; text-align: start; cursor: pointer;
}
#researchbee-app .rb-journal-choices :is(.mode-btn, .rb-choice-btn)::before,
#researchbee-app .rb-journal-choices :is(.mode-btn, .rb-choice-btn)::after { display: none !important; }
#researchbee-app .rb-journal-choices :is(.mode-btn, .rb-choice-btn):hover { background: #f6f8fc !important; border-color: #8799b8 !important; }
#researchbee-app .rb-choice-number {
display: inline-flex; align-items: center; justify-content: center;
flex: 0 0 38px; width: 38px; height: 38px; border-radius: 50%;
background: #EBF1FA; color: #2059A8; font: 750 19px/1 "Open Sans", Arial, sans-serif;
}
#researchbee-app .rb-journal-choices .mode-title { color: #001B48 !important; font: 700 22px/1.3 "Open Sans", Arial, sans-serif !important; }
#researchbee-app .rb-journal-choices .mode-desc { display: block; margin-top: 9px; color: #526074; font: 400 16px/1.6 "Open Sans", Arial, sans-serif; }
#researchbee-app .rb-choice-action { display: block; margin-top: 15px; color: #334f7d; font-size: 14px; font-weight: 650; text-decoration: underline; text-underline-offset: 3px; }
#researchbee-app .rb-mode-back { margin-bottom: 16px; }
#researchbee-app .rb-back-options { border-color: transparent; background: transparent; padding-inline: 0; color: #334f7d; }
#researchbee-app .rb-data-notice { padding: 12px 15px; margin-bottom: 18px; font-size: 14px; background: #fff; }
#researchbee-app .rb-data-notice > p { line-height: 1.6; }
#researchbee-app .rb-data-notice details { margin-top: 6px; }
#researchbee-app .rb-data-notice summary { color: #334f7d; font-weight: 600; cursor: pointer; width: fit-content; min-height: 28px; }
#researchbee-app .rb-data-notice details p { margin-top: 8px; color: #526074; }
#researchbee-app #rb-chat-launcher { padding: 9px 14px; gap: 9px; }
#researchbee-app .rb-launcher-label-top { display: none; }
#researchbee-app .rb-launcher-label-main { font: 650 14px/1.4 "Open Sans", Arial, sans-serif; }
#researchbee-app #rb-chat-launcher .rb-launcher-icon { width: 34px; height: 34px; }
#researchbee-app[dir="rtl"] .rb-journal-choices h2 { letter-spacing: normal; }
@media (max-width: 650px) {
#researchbee-app .rb-workflow-header { padding: 22px 12px 14px; flex-wrap: wrap; gap: 10px; }
#researchbee-app .rb-workflow-header h2 { font-size: 21px; }
#researchbee-app .tabs-bar .tabs-inner { grid-template-columns: 1fr; padding: 0 12px !important; gap: 8px !important; }
#researchbee-app .tabs-bar .tab-btn { padding: 13px 14px !important; }
#researchbee-app .tabs-bar .tab-label-main { font-size: 17px !important; }
#researchbee-app .tabs-bar .tab-label-sub { display: none !important; }
#researchbee-app .rb-journal-choices .mode-selector { grid-template-columns: 1fr; gap: 12px; margin-top: 20px; }
#researchbee-app .rb-journal-choices :is(.mode-btn, .rb-choice-btn) { padding: 20px 16px !important; gap: 12px; }
#researchbee-app .rb-journal-choices .mode-title { font-size: 20px !important; }
#researchbee-app .rb-journal-choices .mode-desc { font-size: 15px; }
}
/* Data repository: introduction, dataset description, sharing requirements. */
#researchbee-app #rb-repo-intro { padding: 8px 0 16px; }
#researchbee-app #rb-repo-intro h2 {
color: #001B48; font: 750 clamp(25px, 3vw, 32px)/1.25 "Open Sans", Arial, sans-serif;
letter-spacing: -.02em; margin: 0 0 10px;
}
#researchbee-app .rb-repo-step-summary {
list-style: none; padding: 0; margin: 24px 0; display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px;
}
#researchbee-app .rb-repo-step-summary li {
display: flex; align-items: flex-start; gap: 14px; background: #fff;
border: 1px solid #d6dce5; border-radius: 0 ; padding: 24px;
}
#researchbee-app .rb-repo-step-summary h3 {
font: 700 21px/1.35 "Open Sans", Arial, sans-serif; color: #001B48; margin: 0 0 8px;
}
#researchbee-app .rb-repo-step-summary p {
font: 400 16px/1.6 "Open Sans", Arial, sans-serif; color: #526074; margin: 0;
}
#researchbee-app .rb-repo-step-label {
color: #92400e; font: 700 13px/1.5 "Open Sans", Arial, sans-serif; margin: 0 0 8px;
}
#researchbee-app .rb-repo-step-actions {
display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 24px;
}
#researchbee-app #rb-repo-intro .btn-primary,
#researchbee-app .rb-repo-step-actions .btn-primary { width: auto; min-width: 200px; }
#researchbee-app #repo-form .rb-step-header h2 {
font: 700 clamp(23px, 2.7vw, 29px)/1.3 "Open Sans", Arial, sans-serif; margin: 0 0 9px;
}
#researchbee-app #repo-form .rb-step-header p { max-width: 760px; }
#researchbee-app #rb-repo-stage-2 > .section-sep:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
@media (max-width: 680px) {
#researchbee-app .rb-repo-step-summary { grid-template-columns: 1fr; gap: 12px; }
#researchbee-app .rb-repo-step-summary li { padding: 20px; }
#researchbee-app .rb-repo-step-actions { align-items: stretch; }
#researchbee-app .rb-repo-step-actions > button { flex: 1 1 100%; }
}
/* v1.9.1: compact journal summaries with alternating, non-semantic colours. */
#researchbee-app #journal-cards-wrap > .rb-discovery-card {
--rb-journal-surface: #f4f8ff;
--rb-journal-head: #edf3fc;
--rb-journal-line: #cad8ed;
--rb-journal-accent: #7d9bc7;
background: var(--rb-journal-surface); border: 1px solid var(--rb-journal-line);
border-inline-start: 4px solid var(--rb-journal-accent);
border-radius: 0 ; box-shadow: 0 2px 7px rgba(26,39,68,.04);
margin-bottom: 12px; min-width: 0;
}
#researchbee-app #journal-cards-wrap > .rb-discovery-card:nth-child(even) {
--rb-journal-surface: #fffaf0;
--rb-journal-head: #fff4df;
--rb-journal-line: #e7d9ba;
--rb-journal-accent: #c4a56c;
}
#researchbee-app #journal-cards-wrap .rb-discovery-card .j-header {
padding: 12px 16px; padding-inline-end: 80px;
background: var(--rb-journal-head); border-bottom-color: var(--rb-journal-line);
}
#researchbee-app #journal-cards-wrap .rb-discovery-card .j-meta { margin-bottom: 3px; font-size: 11.5px; overflow-wrap: anywhere; }
#researchbee-app #journal-cards-wrap .rb-discovery-card .j-title {
font-family: "Open Sans", Arial, sans-serif; font-weight: 700; font-size: 20px;
line-height: 1.35; margin-bottom: 7px; color: #001B48; overflow-wrap: anywhere;
}
#researchbee-app #journal-cards-wrap .rb-discovery-card .rb-identity-row { gap: 5px; }
#researchbee-app #journal-cards-wrap .rb-discovery-card .rb-fit-score {
top: 12px; right: auto; left: auto; inset-inline-end: 14px;
width: 50px; height: 50px; box-shadow: none; border-width: 2px;
border-color: var(--rb-journal-line);
}
#researchbee-app #journal-cards-wrap .rb-discovery-card .rb-fit-score strong { font-size: 17px; }
#researchbee-app #journal-cards-wrap .rb-discovery-card .rb-fit-score span { font-size: 8px; }
#researchbee-app #journal-cards-wrap .rb-discovery-card .rb-card-select { margin-top: 7px; font-size: 12px; min-height: 28px; }
#researchbee-app #journal-cards-wrap .rb-discovery-card .j-body {
padding: 12px 16px; gap: 10px; background: transparent;
}
#researchbee-app #journal-cards-wrap .rb-card-fit h5 { color: #001B48; font-size: 13px; margin-bottom: 3px; }
#researchbee-app #journal-cards-wrap .rb-card-fit p { color: #475569; font-size: 13px; line-height: 1.55; }
#researchbee-app #journal-cards-wrap .rb-card-ranking-note { font-size: 11.5px; line-height: 1.5; color: #526074; }
#researchbee-app #journal-cards-wrap .rb-card-ranking-note strong { color: #334155; }
#researchbee-app #journal-cards-wrap .rb-card-primary-actions { margin: 0; gap: 7px; }
#researchbee-app #journal-cards-wrap .rb-card-primary-actions .rb-cover-letter-notice,
#researchbee-app #journal-cards-wrap .rb-card-primary-actions [id^="cover-letter-"] { flex-basis: 100%; width: 100%; min-width: 0; }
#researchbee-app #journal-cards-wrap .rb-card-primary-actions .rb-refine-btn,
#researchbee-app #journal-cards-wrap .rb-card-primary-actions .rb-cover-letter-btn { min-height: 36px; padding: 7px 11px; }
#researchbee-app #journal-cards-wrap .rb-journal-details {
border-top: 1px solid var(--rb-journal-line); margin-top: 1px;
}
#researchbee-app #journal-cards-wrap .rb-journal-details > summary {
color: #243c62; cursor: pointer; min-height: 44px; padding: 11px 0 7px;
font-size: 13px; line-height: 1.5; font-weight: 700;
}
#researchbee-app #journal-cards-wrap .rb-journal-details > summary:hover { color: #2059A8; }
#researchbee-app #journal-cards-wrap .rb-journal-details .rb-details-open-label { display: none; }
#researchbee-app #journal-cards-wrap .rb-journal-details[open] > summary .rb-details-closed-label { display: none; }
#researchbee-app #journal-cards-wrap .rb-journal-details[open] > summary .rb-details-open-label { display: inline; }
#researchbee-app #journal-cards-wrap .rb-journal-details-body { display: flex; flex-direction: column; gap: 10px; padding-top: 5px; }
#researchbee-app #journal-cards-wrap .rb-journal-details-body > * { min-width: 0; }
#researchbee-app #journal-cards-wrap .rb-journal-details .detail-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
#researchbee-app #journal-cards-wrap .rb-journal-details .detail-item { min-width: 0; }
#researchbee-app #journal-cards-wrap .rb-journal-details .detail-item p { font-size: 12px; line-height: 1.55; }
#researchbee-app #journal-cards-wrap .rb-journal-details .rb-section-grid { gap: 10px; }
#researchbee-app #journal-cards-wrap .rb-journal-details .rb-info-panel,
#researchbee-app #journal-cards-wrap .rb-journal-details .rb-fit-breakdown,
#researchbee-app #journal-cards-wrap .rb-journal-details .rank-box { padding: 10px 12px; }
#researchbee-app #journal-cards-wrap .rb-journal-details .rb-evidence { padding-top: 9px; }
@media (max-width: 640px) {
#researchbee-app #journal-cards-wrap .rb-discovery-card .j-header { padding: 11px 12px; padding-inline-end: 72px; }
#researchbee-app #journal-cards-wrap .rb-discovery-card .j-title { font-size: 18px; }
#researchbee-app #journal-cards-wrap .rb-discovery-card .j-body { padding: 11px 12px; }
#researchbee-app #journal-cards-wrap .rb-discovery-card .rb-fit-score { inset-inline-end: 11px; }
#researchbee-app #journal-cards-wrap .rb-journal-details .detail-grid,
#researchbee-app #journal-cards-wrap .rb-journal-details .rb-section-grid { grid-template-columns: 1fr; }
#researchbee-app #journal-cards-wrap .rb-card-primary-actions .rb-refine-btn,
#researchbee-app #journal-cards-wrap .rb-card-primary-actions .rb-cover-letter-btn { min-height: 44px; }
}
/* v1.9.2: feedback link with a brief, gentle invitation animation. */
#researchbee-app .rb-feedback-link {
margin-inline-start: auto; display: inline-flex; align-items: center; gap: 9px;
min-height: 42px; padding: 9px 15px; border: 1px solid #f5ce78; border-radius: 0 ;
background: #fff2c8;
color: #28334a; font: 750 14px/1.4 "Open Sans", Arial, sans-serif; text-decoration: none;
box-shadow: 0 2px 8px rgba(0,0,0,.12); white-space: nowrap;
transition: background .18s, box-shadow .18s, transform .18s;
}
#researchbee-app .rb-feedback-link:hover {
background: #ffe5a3; color: #17243d; text-decoration: none;
box-shadow: 0 3px 12px rgba(0,0,0,.2); transform: translateY(-1px);
}
#researchbee-app .rb-feedback-link:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }
#researchbee-app .rb-feedback-icon {
flex: 0 0 auto; transform-origin: center;
animation: rb-feedback-nudge 1.35s ease-in-out .3s 3;
}
#researchbee-app .rb-feedback-arrow { flex: 0 0 auto; opacity: .7; }
@keyframes rb-feedback-nudge {
0%, 65%, 100% { transform: translateY(0) rotate(0deg); }
20% { transform: translateY(-2px) rotate(-8deg); }
40% { transform: translateY(-1px) rotate(6deg); }
}
@media (max-width: 480px) {
#researchbee-app .rb-feedback-link { padding: 8px 12px; font-size: 13px; gap: 7px; }
}
@media (prefers-reduced-motion: reduce) {
#researchbee-app .rb-feedback-icon { animation: none !important; }
#researchbee-app .rb-feedback-link { transition: none; }
#researchbee-app .rb-feedback-link:hover { transform: none; }
}
#researchbee-app .rb-trusted-links {display:flex;flex-wrap:wrap;gap:8px;padding:10px 0;font-size:12px;}
.rb-trusted-links > div {display:flex;flex-direction:column;gap:3px;}
.rb-trusted-links small {display:block;font-size:11px;font-weight:normal;overflow-wrap:anywhere;}
.j-title a {color:inherit;text-decoration:underline;text-underline-offset:3px;}
/* =============================================================
KHALIFA UNIVERSITY STYLE LAYER — ResearchBee
Follows www.ku.ac.ae: Open Sans text, PT Sans uppercase titles
with a short rule, KU blue navigation, flat colour tiles,
square corners, no gradients or decorative shadows.
============================================================= */
#researchbee-app.rb-ku {
--primary: #2059A8; --primary-dark: #174483; --primary-light: #EBF1FA; --primary-xlight: #F4F7FC;
--text: #333A42; --text-muted: #5E6772; --border: #DDE2E8; --border-strong: #C4CBD4; --bg-subtle: #FFFFFF;
--ku-navy: #001B48; --ku-navy-2: #0A2D66; --ku-blue: #2059A8; --ku-blue-dark: #174483; --ku-sky: #6FA8E8;
--ku-purple: #5B3F8C; --ku-grey: #6D7480; --ku-title: #3E3E3E; --ku-line: #DDE2E8; --ku-soft: #F4F6F9; --ku-tint: #EBF1FA;
--ku-head: "PT Sans", "Open Sans", Arial, sans-serif;
min-height: 0; background: #fff; color: #333A42;
font-family: "Open Sans", Arial, sans-serif; font-size: 15px;
}
#researchbee-app.rb-ku :is(button, a, summary, input, textarea, select):focus-visible { outline: 3px solid var(--ku-sky) !important; outline-offset: 2px !important; }
#researchbee-app.rb-ku .rb-ku-shell { width: min(1170px, calc(100% - 40px)); margin: 0 auto; }
/* ---------- Header ---------- */
#researchbee-app.rb-ku .rb-ku-header { background: #fff; border-bottom: 1px solid var(--ku-line); }
#researchbee-app.rb-ku .rb-ku-header-inner { display: flex; align-items: center; gap: 20px; min-height: 76px; padding: 12px 0; }
#researchbee-app.rb-ku .rb-ku-logo { display: inline-flex; flex: 0 0 auto; padding-inline-end: 20px; border-inline-end: 1px solid var(--ku-line); }
#researchbee-app.rb-ku .rb-ku-logo img { display: block; width: auto !important; height: 42px !important; max-width: none !important; }
#researchbee-app.rb-ku .rb-ku-brand { display: flex; flex-direction: column; min-width: 0; }
#researchbee-app.rb-ku .rb-ku-brand-name { color: var(--ku-navy); font: 700 26px/1.1 var(--ku-head); }
#researchbee-app.rb-ku .rb-ku-brand-sub { margin-top: 3px; color: var(--text-muted); font-size: 12.5px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; }
/* Language + feedback: quiet controls on the right of the header */
#researchbee-app.rb-ku .rb-libguide-toolbar { margin-inline-start: auto; background: transparent; color: var(--text); border-radius: 0; }
#researchbee-app.rb-ku .rb-libguide-toolbar .model-bar-inner { display: flex; align-items: center; gap: 10px; max-width: none; padding: 0; background: transparent; }
#researchbee-app.rb-ku .rb-libguide-toolbar .model-label { color: var(--text-muted); font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
#researchbee-app.rb-ku .model-toggle { display: inline-flex; gap: 0; padding: 0; border: 1px solid var(--border-strong); border-radius: 0; background: #fff; }
#researchbee-app.rb-ku .lang-btn { min-width: 40px; min-height: 34px; padding: 4px 10px; border: 0; border-radius: 0; background: #fff; color: var(--ku-blue); font: 700 12.5px/1 "Open Sans", Arial, sans-serif; box-shadow: none; }
#researchbee-app.rb-ku .lang-btn.active { background: var(--ku-blue); color: #fff; }
#researchbee-app.rb-ku .lang-btn:hover:not(.active) { background: var(--ku-tint); }
#researchbee-app.rb-ku .rb-feedback-link {
margin-inline-start: 6px; min-height: 36px; padding: 6px 14px; gap: 8px; border: 1px solid var(--ku-blue); border-radius: 0;
background: #fff; color: var(--ku-blue); box-shadow: none; font: 700 12.5px/1.3 "Open Sans", Arial, sans-serif; letter-spacing: .03em; text-transform: uppercase;
}
#researchbee-app.rb-ku .rb-feedback-link:hover { background: var(--ku-blue); color: #fff; box-shadow: none; transform: none; }
#researchbee-app.rb-ku .rb-feedback-icon { animation: none; }
/* KU blue link bar */
#researchbee-app.rb-ku .rb-ku-nav { background: var(--ku-blue); }
#researchbee-app.rb-ku .rb-ku-nav-inner { display: flex; overflow-x: auto; scrollbar-width: none; }
#researchbee-app.rb-ku .rb-ku-nav-inner::-webkit-scrollbar { display: none; }
#researchbee-app.rb-ku .rb-ku-nav a {
position: relative; display: inline-flex; align-items: center; flex: 0 0 auto; min-height: 46px; padding: 0 16px;
color: #fff; font-size: 13.5px; font-weight: 600; text-transform: uppercase; text-decoration: none; white-space: nowrap;
}
#researchbee-app.rb-ku .rb-ku-nav a:first-child { padding-inline-start: 0; }
#researchbee-app.rb-ku .rb-ku-nav a + a::before { content: ""; position: absolute; inset-inline-start: 0; top: 50%; width: 1px; height: 14px; margin-top: -7px; background: rgba(255,255,255,.55); }
#researchbee-app.rb-ku .rb-ku-nav a::after { content: ""; position: absolute; left: 16px; right: 16px; bottom: 9px; height: 2px; background: #fff; transform: scaleX(0); transition: transform .18s ease; }
#researchbee-app.rb-ku .rb-ku-nav a:first-child::after { left: 0; }
#researchbee-app.rb-ku[dir="rtl"] .rb-ku-nav a:first-child::after { left: 16px; right: 0; }
#researchbee-app.rb-ku .rb-ku-nav a:hover::after { transform: scaleX(1); }
/* ---------- Hero ---------- */
#researchbee-app.rb-ku .rb-purpose { position: relative; overflow: hidden; border-top: 0; background: var(--ku-navy); color: #fff; }
#researchbee-app.rb-ku .rb-purpose::before,
#researchbee-app.rb-ku .rb-purpose::after { content: ""; position: absolute; top: 0; bottom: 0; inset-inline-end: 0; pointer-events: none; }
#researchbee-app.rb-ku .rb-purpose::before { width: 32%; background: var(--ku-blue); clip-path: polygon(28% 0, 100% 0, 100% 100%, 0 100%); }
#researchbee-app.rb-ku .rb-purpose::after { width: 14%; background: #2E6BC0; clip-path: polygon(45% 0, 100% 0, 100% 100%, 0 100%); opacity: .85; }
#researchbee-app.rb-ku[dir="rtl"] .rb-purpose::before { clip-path: polygon(0 0, 72% 0, 100% 100%, 0 100%); }
#researchbee-app.rb-ku[dir="rtl"] .rb-purpose::after { clip-path: polygon(0 0, 55% 0, 100% 100%, 0 100%); }
#researchbee-app.rb-ku .rb-purpose-inner {
position: relative; z-index: 1; display: flex; align-items: center; justify-content: space-between; gap: 28px;
width: min(1170px, calc(100% - 40px)); max-width: none; margin: 0 auto; padding: 44px 0 46px;
}
#researchbee-app.rb-ku .rb-purpose-heading { min-width: 0; max-width: 660px; }
#researchbee-app.rb-ku .rb-purpose-kicker { margin: 0 0 12px; color: #C7D3E6; font-size: 12.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; }
#researchbee-app.rb-ku .rb-purpose h1 {
position: relative; margin: 0 0 18px; padding-bottom: 16px; color: #fff;
font: 700 clamp(30px, 4vw, 44px)/1.08 var(--ku-head); letter-spacing: 0; text-transform: uppercase;
}
#researchbee-app.rb-ku .rb-purpose h1::after { content: ""; position: absolute; inset-inline-start: 0; bottom: 0; width: 60px; height: 4px; background: var(--ku-sky); }
#researchbee-app.rb-ku .rb-purpose-tagline { margin: 0; color: #E3EAF5; font-size: 18px; line-height: 1.5; }
#researchbee-app.rb-ku .rb-purpose-mascot { position: relative; flex: 0 0 auto; margin-inline-end: 6%; padding: 14px; background: #fff; }
#researchbee-app.rb-ku .rb-purpose-mascot::before { content: ""; position: absolute; inset: 14px -14px -14px 14px; z-index: -1; border: 2px solid #fff; }
#researchbee-app.rb-ku .rb-purpose-image { display: block; width: 140px; height: 140px; object-fit: contain; }
/* Slim "looking for articles" strip */
#researchbee-app.rb-ku .rb-purpose-search { position: relative; z-index: 1; border-top: 0; background: var(--ku-soft); color: var(--text); }
#researchbee-app.rb-ku .rb-purpose-search-inner { width: min(1170px, calc(100% - 40px)); max-width: none; margin: 0 auto; padding: 14px 0; gap: 16px; }
#researchbee-app.rb-ku .rb-purpose-search-copy { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; }
#researchbee-app.rb-ku .rb-purpose-search-copy strong { display: inline; color: var(--ku-navy); font-size: 14.5px; font-weight: 700; }
#researchbee-app.rb-ku .rb-purpose-search-copy p { margin: 0; color: var(--text-muted); font-size: 14px; }
#researchbee-app.rb-ku .rb-purpose-links { gap: 6px; }
#researchbee-app.rb-ku .rb-purpose-link {
min-height: 36px; padding: 6px 14px; border: 1px solid var(--ku-blue); border-radius: 0; background: #fff; color: var(--ku-blue);
font: 700 12.5px/1.3 "Open Sans", Arial, sans-serif; letter-spacing: .03em; text-transform: uppercase;
}
#researchbee-app.rb-ku .rb-purpose-link:hover { background: var(--ku-blue); border-color: var(--ku-blue); color: #fff; }
/* ---------- Section titles ---------- */
#researchbee-app.rb-ku :is(.rb-workflow-header h2, .rb-journal-choices h2, #rb-repo-intro h2) {
position: relative; margin: 0 0 12px; padding-bottom: 14px; color: var(--ku-title);
font: 700 clamp(23px, 2.6vw, 28px)/1.15 var(--ku-head); letter-spacing: 0; text-transform: uppercase;
}
#researchbee-app.rb-ku :is(.rb-workflow-header h2, .rb-journal-choices h2, #rb-repo-intro h2)::after {
content: ""; position: absolute; inset-inline-start: 0; bottom: 0; width: 50px; height: 4px; background: var(--ku-title);
}
#researchbee-app.rb-ku .rb-choice-intro { color: var(--text-muted); font-size: 15.5px; }
/* ---------- Function tiles (the three tabs) ---------- */
#researchbee-app.rb-ku .rb-workflow-header { width: min(1170px, calc(100% - 40px)); max-width: none; margin: 0 auto; padding: 48px 0 10px; align-items: flex-end; }
#researchbee-app.rb-ku .rb-workflow-header h2 { margin-bottom: 0; }
#researchbee-app.rb-ku[dir="rtl"] :is(.rb-workflow-header h2, .rb-journal-choices h2, #rb-repo-intro h2) { padding-bottom: 20px; }
#researchbee-app.rb-ku .rb-clear-all {
min-height: 36px; padding: 6px 14px; border: 1px solid var(--ku-blue); border-radius: 0; background: #fff; color: var(--ku-blue);
font: 700 12.5px/1.3 "Open Sans", Arial, sans-serif; letter-spacing: .03em; text-transform: uppercase;
}
#researchbee-app.rb-ku .rb-clear-all:hover { background: var(--ku-blue); border-color: var(--ku-blue); color: #fff; }
#researchbee-app.rb-ku[data-rb-view="home"] .rb-clear-all { display: none; }
#researchbee-app.rb-ku .tabs-bar { margin-top: 20px; background: transparent !important; border: 0 !important; box-shadow: none !important; }
#researchbee-app.rb-ku .tabs-bar .tabs-inner {
display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px !important;
width: min(1170px, calc(100% - 40px)); max-width: none; margin: 0 auto; padding: 0 !important; overflow: visible !important;
}
#researchbee-app.rb-ku .tabs-bar .tab-btn {
--rb-tab-colour: var(--ku-blue);
position: relative; display: flex !important; flex-direction: column !important; align-items: flex-start !important; justify-content: flex-start;
gap: 16px !important; min-height: 190px; padding: 24px 24px 54px !important; overflow: visible;
border: 0 !important; border-radius: 0 !important; background: var(--rb-tab-colour) !important; color: #fff;
box-shadow: none !important; transform: none !important; filter: none !important; text-align: start; cursor: pointer;
transition: background-color .18s ease !important;
}
#researchbee-app.rb-ku .tabs-bar .tab-btn[data-tab="license"] { --rb-tab-colour: var(--ku-navy); }
#researchbee-app.rb-ku .tabs-bar .tab-btn[data-tab="data"] { --rb-tab-colour: var(--ku-purple); }
#researchbee-app.rb-ku .tabs-bar .tab-btn:hover { background: var(--ku-blue-dark) !important; }
#researchbee-app.rb-ku .tabs-bar .tab-btn[data-tab="license"]:hover { background: #0B2A63 !important; }
#researchbee-app.rb-ku .tabs-bar .tab-btn[data-tab="data"]:hover { background: #4A3274 !important; }
#researchbee-app.rb-ku .rb-function-number {
flex: 0 0 auto; width: 38px; height: 38px; border: 2px solid rgba(255,255,255,.75); border-radius: 0 !important;
background: transparent !important; color: #fff !important; font: 700 18px/1 var(--ku-head);
}
#researchbee-app.rb-ku .tabs-bar .tab-label-wrap { display: block; min-width: 0; overflow: visible !important; }
#researchbee-app.rb-ku .tabs-bar .tab-label-main {
display: block; color: #fff !important; font: 700 17px/1.3 "Open Sans", Arial, sans-serif !important;
text-transform: uppercase; white-space: normal !important; overflow: visible !important; text-overflow: clip !important;
}
#researchbee-app.rb-ku .tabs-bar .tab-label-sub {
display: block !important; margin-top: 8px; color: rgba(255,255,255,.84) !important;
font-size: 14px !important; font-weight: 400; line-height: 1.55 !important; text-transform: none;
}
#researchbee-app.rb-ku .rb-ku-tab-arrow { position: absolute; inset-inline-end: 22px; bottom: 22px; color: #fff; transition: transform .18s ease; }
#researchbee-app.rb-ku[dir="rtl"] .rb-ku-tab-arrow { transform: scaleX(-1); }
#researchbee-app.rb-ku .tabs-bar .tab-btn:hover .rb-ku-tab-arrow { transform: translateX(4px); }
#researchbee-app.rb-ku[dir="rtl"] .tabs-bar .tab-btn:hover .rb-ku-tab-arrow { transform: scaleX(-1) translateX(4px); }
/* Selected function: a light bar and a notch pointing to the workspace below */
#researchbee-app.rb-ku .tabs-bar .tab-btn.active { box-shadow: inset 0 -5px 0 var(--ku-sky) !important; }
#researchbee-app.rb-ku .tabs-bar .tab-btn.active::after {
content: ""; position: absolute; inset-inline-start: 34px; bottom: -11px; width: 22px; height: 22px;
background: var(--ku-sky); transform: rotate(45deg); z-index: -1;
}
#researchbee-app.rb-ku .tabs-bar .tab-btn.active .rb-ku-tab-arrow { transform: rotate(90deg); }
#researchbee-app.rb-ku:not([data-rb-view="home"]) .tabs-bar .tab-btn:not(.active) .tab-label-sub { color: rgba(255,255,255,.7) !important; }
/* ---------- Workspace ---------- */
#researchbee-app.rb-ku .main-content { width: min(1170px, calc(100% - 40px)); max-width: none; margin: 0 auto; padding: 30px 0 40px !important; }
#researchbee-app.rb-ku #rb-home-view { padding: 0; color: var(--text-muted); font-size: 15px; }
#researchbee-app.rb-ku .ar-banner { border-radius: 0; }
#researchbee-app.rb-ku .rb-data-notice { padding: 12px 16px; border: 0; border-inline-start: 4px solid #C99A2E; border-radius: 0; background: #FDF8EC; color: #4A3B12; font-size: 13.5px; }
#researchbee-app.rb-ku .rb-data-notice summary { color: var(--ku-blue); }
/* Choice cards (journal options, sharing options) */
#researchbee-app.rb-ku .rb-journal-choices { padding: 0 0 8px; }
#researchbee-app.rb-ku .rb-journal-choices .mode-selector { gap: 20px; margin-top: 22px; }
#researchbee-app.rb-ku .rb-journal-choices :is(.mode-btn, .rb-choice-btn) {
gap: 16px; padding: 24px !important; border: 1px solid var(--ku-line) !important; border-top: 4px solid var(--ku-blue) !important;
border-radius: 0 !important; background: #fff !important; transition: border-color .15s ease, background-color .15s ease;
}
#researchbee-app.rb-ku .rb-journal-choices :is(.mode-btn, .rb-choice-btn):nth-child(2) { border-top-color: var(--ku-navy) !important; }
#researchbee-app.rb-ku .rb-journal-choices :is(.mode-btn, .rb-choice-btn):hover { background: #FAFBFD !important; border-color: #B9C3CF !important; border-top-color: var(--ku-blue) !important; }
#researchbee-app.rb-ku .rb-choice-number {
flex: 0 0 38px; width: 38px; height: 38px; border-radius: 0 !important; background: var(--ku-blue) !important; color: #fff !important; font: 700 18px/1 var(--ku-head);
}
#researchbee-app.rb-ku .rb-journal-choices .mode-title { color: var(--ku-navy) !important; font: 700 20px/1.3 var(--ku-head) !important; text-transform: uppercase; }
#researchbee-app.rb-ku .rb-journal-choices .mode-desc { margin-top: 8px; color: var(--text-muted); font: 400 15px/1.6 "Open Sans", Arial, sans-serif; }
#researchbee-app.rb-ku .rb-choice-action { margin-top: 16px; color: var(--ku-blue); font-size: 12.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; text-decoration: none; }
#researchbee-app.rb-ku .rb-choice-action::after { content: "\00a0\203A"; }
/* Data repository overview */
#researchbee-app.rb-ku .rb-repo-step-summary { gap: 20px; }
#researchbee-app.rb-ku .rb-repo-step-summary li { border: 1px solid var(--ku-line); border-top: 4px solid var(--ku-purple); border-radius: 0; padding: 24px; }
#researchbee-app.rb-ku .rb-repo-step-summary .rb-choice-number { background: var(--ku-purple) !important; }
#researchbee-app.rb-ku .rb-repo-step-summary h3 { color: var(--ku-navy); font: 700 19px/1.3 var(--ku-head); text-transform: uppercase; }
#researchbee-app.rb-ku .rb-repo-step-summary p { color: var(--text-muted); font-size: 15px; }
#researchbee-app.rb-ku .rb-repo-step-label { color: var(--ku-purple); font-size: 12px; letter-spacing: .08em; text-transform: uppercase; }
/* Back links */
#researchbee-app.rb-ku .rb-back-options {
min-height: 36px; padding: 6px 0; border: 0; background: transparent; color: var(--ku-blue);
font: 700 12.5px/1.3 "Open Sans", Arial, sans-serif; letter-spacing: .03em; text-transform: uppercase;
}
#researchbee-app.rb-ku .rb-back-options::before { content: "\2039\00a0"; font-size: 16px; }
#researchbee-app.rb-ku .rb-back-options:hover { background: transparent; text-decoration: underline; text-underline-offset: 3px; }
/* Form cards */
#researchbee-app.rb-ku .card { border: 1px solid var(--ku-line); border-top: 4px solid var(--ku-blue); border-radius: 0; background: #fff; box-shadow: none; overflow: visible; }
#researchbee-app.rb-ku #mode-manuscript .card { border-top-color: var(--ku-navy); }
#researchbee-app.rb-ku #license-form .card { border-top-color: var(--ku-navy); }
#researchbee-app.rb-ku #repo-form .card { border-top-color: var(--ku-purple); }
#researchbee-app.rb-ku .card-header { padding: 22px 26px 18px; border-bottom: 1px solid var(--ku-line); background: #fff; }
#researchbee-app.rb-ku .card-header h2,
#researchbee-app.rb-ku #repo-form .rb-step-header h2 { color: var(--ku-navy); font: 700 22px/1.3 var(--ku-head); letter-spacing: 0; }
#researchbee-app.rb-ku .card-header p { margin-top: 6px; color: var(--text-muted); font-size: 14px; line-height: 1.6; }
#researchbee-app.rb-ku .card-body { padding: 24px 26px 26px; }
#researchbee-app.rb-ku .form-group label { color: var(--ku-navy); font-size: 13.5px; font-weight: 700; }
#researchbee-app.rb-ku :is(.form-group input[type="text"], .form-group input[type="number"], .form-group textarea, .form-group select) {
border: 1px solid var(--border-strong); border-radius: 0; background: #fff; box-shadow: none; font-size: 15px;
transition: border-color .15s ease, box-shadow .15s ease;
}
#researchbee-app.rb-ku :is(.form-group input, .form-group textarea, .form-group select):focus { border-color: var(--ku-blue); box-shadow: inset 0 0 0 1px var(--ku-blue); outline: none; }
#researchbee-app.rb-ku .field-hint { color: var(--text-muted); font-size: 12.5px; }
#researchbee-app.rb-ku :is(.req) { color: #B3261E; }
#researchbee-app.rb-ku .recommended,
#researchbee-app.rb-ku .rb-planning-only { border-radius: 0; }
#researchbee-app.rb-ku .section-sep { border-top: 1px solid var(--ku-line); }
#researchbee-app.rb-ku .section-label { color: var(--ku-title); font: 700 13px/1.4 "Open Sans", Arial, sans-serif; letter-spacing: .06em; text-transform: uppercase; }
#researchbee-app.rb-ku .rb-advanced { margin-top: 18px; border: 1px solid var(--ku-line); border-radius: 0; background: #fff; }
#researchbee-app.rb-ku .rb-advanced > summary { padding: 12px 16px; background: var(--ku-soft); color: var(--ku-blue); font-size: 12.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; }
#researchbee-app.rb-ku .rb-advanced[open] > summary { border-bottom: 1px solid var(--ku-line); background: var(--ku-soft); }
#researchbee-app.rb-ku .btn { border-radius: 0; box-shadow: none; transform: none; }
#researchbee-app.rb-ku .btn-primary {
width: auto; min-width: 220px; min-height: 48px; padding: 0 26px; border: 0; background: var(--ku-blue); color: #fff;
font: 700 13.5px/1.2 "Open Sans", Arial, sans-serif; letter-spacing: .04em; text-transform: uppercase;
}
#researchbee-app.rb-ku .btn-primary:hover:not(:disabled) { background: var(--ku-blue-dark); transform: none; box-shadow: none; }
#researchbee-app.rb-ku .btn-ghost { border-radius: 0; }
/* Results: keep the existing renderer, align its frame with KU */
#researchbee-app.rb-ku #journal-cards-wrap > .rb-discovery-card { border-radius: 0; box-shadow: none; --rb-journal-surface: #fff; --rb-journal-head: #F4F7FC; --rb-journal-line: #DDE2E8; --rb-journal-accent: var(--ku-blue); }
#researchbee-app.rb-ku #journal-cards-wrap > .rb-discovery-card:nth-child(even) { --rb-journal-surface: #fff; --rb-journal-head: #F6F4FA; --rb-journal-line: #E2DDEB; --rb-journal-accent: var(--ku-purple); }
#researchbee-app.rb-ku #journal-cards-wrap .rb-discovery-card .j-title { color: var(--ku-navy); font-family: var(--ku-head); }
/* Inline indigo set by the script */
#researchbee-app.rb-ku [style*="background:#e0e7ff"] { background: var(--ku-tint) !important; color: var(--ku-blue-dark) !important; border-radius: 0 !important; }
#researchbee-app.rb-ku [style*="color:#4338CA"] { color: var(--ku-blue) !important; }
#researchbee-app.rb-ku [style*="Georgia"] { font-family: var(--ku-head) !important; color: var(--ku-navy); text-transform: uppercase; font-size: 20px !important; }
#researchbee-app.rb-ku .results-title { color: var(--ku-title); font: 700 24px/1.2 var(--ku-head); text-transform: uppercase; }
/* ---------- Footer ---------- */
#researchbee-app.rb-ku .site-footer { margin-top: 24px; padding: 28px 0 32px; border-top: 4px solid var(--ku-navy); background: var(--ku-soft); }
#researchbee-app.rb-ku .footer-inner { width: min(1170px, calc(100% - 40px)); max-width: none; margin: 0 auto; color: var(--text-muted); font-size: 12.5px; line-height: 1.65; }
#researchbee-app.rb-ku .footer-inner a { color: var(--ku-blue); font-weight: 600; }
#researchbee-app.rb-ku .rb-version-badge { border-radius: 0; }
#researchbee-app.rb-ku .footer-sources { max-width: none; margin: 12px 0 0; padding-top: 12px; border-top: 1px solid var(--ku-line); color: var(--text-muted); font-size: 12px; text-align: start; }
/* ---------- Chat ---------- */
#researchbee-app.rb-ku #rb-chat-launcher { border-radius: 0; background: var(--ku-navy); box-shadow: 0 6px 18px rgba(0,27,72,.28); padding: 8px 16px 8px 8px; }
#researchbee-app.rb-ku #rb-chat-launcher:hover { background: var(--ku-blue); transform: none; box-shadow: 0 6px 18px rgba(0,27,72,.28); }
#researchbee-app.rb-ku .rb-launcher-label-main { font: 700 13px/1.3 "Open Sans", Arial, sans-serif; letter-spacing: .03em; text-transform: uppercase; }
#researchbee-app.rb-ku :is(.rb-launcher-icon, .rb-mobile-bar-icon) { border-radius: 0 !important; }
#researchbee-app.rb-ku #rb-chat-tooltip { border-radius: 0; background: var(--ku-navy); }
#researchbee-app.rb-ku #rb-chat-panel { border-radius: 0; border-top: 4px solid var(--ku-blue); }
#researchbee-app.rb-ku .rb-chat-header { background: var(--ku-navy); }
#researchbee-app.rb-ku .rb-chat-header img { border-radius: 0; }
#researchbee-app.rb-ku .rb-chat-header-name { font-family: var(--ku-head); }
#researchbee-app.rb-ku .rb-msg.user .rb-bubble { background: var(--ku-blue); border-radius: 0; }
#researchbee-app.rb-ku .rb-msg.assistant .rb-bubble { border-radius: 0; border-inline-start: 3px solid var(--ku-blue); }
#researchbee-app.rb-ku #rb-chat-send { border-radius: 0; background: var(--ku-blue); }
#researchbee-app.rb-ku #rb-chat-input { border-radius: 0; }
#researchbee-app.rb-ku #rb-mobile-chat-bar { background: var(--ku-navy); }
/* Intro dialog (opened from code only) */
#researchbee-app.rb-ku .rb-service-intro { border-radius: 0; border-top: 4px solid var(--ku-blue); }
/* LibGuides / Bootstrap hardening */
#researchbee-app.rb-ku h1, #researchbee-app.rb-ku h2, #researchbee-app.rb-ku h3 { margin-top: 0; }
#researchbee-app.rb-ku a.rb-purpose-link, #researchbee-app.rb-ku .rb-ku-nav a, #researchbee-app.rb-ku .rb-feedback-link { text-decoration: none !important; }
/* ---------- Responsive ---------- */
@media (max-width: 980px) {
#researchbee-app.rb-ku .rb-ku-brand-sub { display: none; }
#researchbee-app.rb-ku .tabs-bar .tab-btn { min-height: 210px; }
}
@media (max-width: 760px) {
#researchbee-app.rb-ku :is(.rb-ku-shell, .rb-purpose-inner, .rb-purpose-search-inner, .rb-workflow-header, .tabs-bar .tabs-inner, .main-content, .footer-inner) { width: calc(100% - 24px); }
#researchbee-app.rb-ku .main-content { padding-left: 0 !important; padding-right: 0 !important; }
#researchbee-app.rb-ku .rb-ku-header-inner { flex-wrap: wrap; gap: 10px 12px; min-height: 0; }
#researchbee-app.rb-ku .rb-ku-logo { padding-inline-end: 12px; }
#researchbee-app.rb-ku .rb-ku-logo img { height: 32px !important; }
#researchbee-app.rb-ku .rb-ku-brand-name { font-size: 21px; }
#researchbee-app.rb-ku .rb-libguide-toolbar { flex: 1 1 100%; margin: 0; }
#researchbee-app.rb-ku .rb-libguide-toolbar .model-bar-inner { justify-content: flex-start; }
#researchbee-app.rb-ku .rb-feedback-link { margin-inline-start: auto; }
#researchbee-app.rb-ku .rb-ku-nav a { min-height: 42px; padding: 0 13px; font-size: 12.5px; }
#researchbee-app.rb-ku .rb-purpose-inner { gap: 16px; padding: 28px 0 30px; }
#researchbee-app.rb-ku .rb-purpose h1 { font-size: 28px; margin-bottom: 14px; padding-bottom: 12px; }
#researchbee-app.rb-ku .rb-purpose-tagline { font-size: 15.5px; }
#researchbee-app.rb-ku .rb-purpose-mascot { margin-inline-end: 10px; padding: 8px; }
#researchbee-app.rb-ku .rb-purpose-mascot::before { inset: 8px -8px -8px 8px; }
#researchbee-app.rb-ku .rb-purpose-image { width: 84px; height: 84px; }
#researchbee-app.rb-ku .rb-purpose-search-inner { flex-direction: column; align-items: stretch; }
#researchbee-app.rb-ku .rb-purpose-links { width: 100%; }
#researchbee-app.rb-ku .rb-purpose-link { flex: 1; }
#researchbee-app.rb-ku .rb-workflow-header { padding-top: 34px; flex-wrap: wrap; }
#researchbee-app.rb-ku .tabs-bar .tabs-inner { grid-template-columns: 1fr; gap: 4px !important; }
#researchbee-app.rb-ku .tabs-bar .tab-btn { flex-direction: row !important; align-items: flex-start !important; min-height: 0; padding: 18px 48px 18px 16px !important; gap: 14px !important; }
#researchbee-app.rb-ku[dir="rtl"] .tabs-bar .tab-btn { padding: 18px 16px 18px 48px !important; }
#researchbee-app.rb-ku .tabs-bar .tab-label-main { font-size: 15px !important; }
#researchbee-app.rb-ku .tabs-bar .tab-label-sub { font-size: 13.5px !important; }
#researchbee-app.rb-ku .rb-function-number { width: 32px; height: 32px; font-size: 16px; }
#researchbee-app.rb-ku .rb-ku-tab-arrow { top: 50%; bottom: auto; inset-inline-end: 16px; margin-top: -10px; }
#researchbee-app.rb-ku .tabs-bar .tab-btn.active::after { inset-inline-start: 24px; }
#researchbee-app.rb-ku .card-header { padding: 18px 16px 14px; }
#researchbee-app.rb-ku .card-body { padding: 18px 16px 20px; }
#researchbee-app.rb-ku .btn-primary { width: 100%; min-width: 0; }
}
@media (max-width: 420px) {
#researchbee-app.rb-ku .rb-libguide-toolbar .model-label { display: none; }
#researchbee-app.rb-ku .rb-purpose-kicker { font-size: 11px; letter-spacing: .1em; }
#researchbee-app.rb-ku .rb-purpose h1 { font-size: 25px; }
#researchbee-app.rb-ku .rb-purpose-image { width: 64px; height: 64px; }
}
</style>
<div id="researchbee-app" class="rb-ku" data-researchbee-version="libguides-1.9.3-links-ku" lang="en" dir="ltr">
<div id="rb-service-intro-backdrop" aria-hidden="true">
<section class="rb-service-intro" id="rb-service-intro" role="dialog" aria-modal="true" aria-labelledby="rb-service-intro-title" tabindex="-1">
<button id="rb-service-intro-close" type="button" aria-label="Close ResearchBee introduction">&times;</button>
<div class="rb-service-intro-head">
<div class="rb-service-intro-kicker"><span aria-hidden="true">&#128029;</span> KU Library research support</div>
<h2 id="rb-service-intro-title">Welcome to ResearchBee</h2>
<p>Your guide to journal selection, open-access sharing, publishing decisions, and research-data repositories.</p>
</div>
<div class="rb-service-intro-body">
<div class="rb-service-list" aria-label="ResearchBee services">
<div class="rb-service-item"><span class="rb-service-item-icon" aria-hidden="true">&#128240;</span><div><strong>Find and compare journals</strong><span>Match your topic or manuscript, then interpret scope, indexing, rankings, and open-access options.</span></div></div>
<div class="rb-service-item"><span class="rb-service-item-icon" aria-hidden="true">&#128737;</span><div><strong>Check article-sharing rights</strong><span>Review permitted versions, embargoes, licences, and deposit options, including Khazna.</span></div></div>
<div class="rb-service-item"><span class="rb-service-item-icon" aria-hidden="true">&#128451;</span><div><strong>Choose a data repository</strong><span>Identify trusted disciplinary, generalist, or institutional repositories for your dataset.</span></div></div>
<div class="rb-service-item"><span class="rb-service-item-icon" aria-hidden="true">&#128172;</span><div><strong>Chat with ResearchBee</strong><span>Ask about KU OA and APC support, journal metrics, publishing tips, FAIR data, RDM, and more.</span></div></div>
</div>
<div class="rb-service-intro-actions">
<button class="rb-service-intro-action" id="rb-service-intro-explore" type="button">Explore the tools</button>
<button class="rb-service-intro-action" id="rb-service-intro-chat" type="button">Chat with ResearchBee</button>
</div>
<p class="rb-service-intro-hint">Click anywhere to close this introduction.</p>
</div>
</section>
</div>
<header class="rb-ku-header">
<div class="rb-ku-shell rb-ku-header-inner">
<a class="rb-ku-logo" href="https://library.ku.ac.ae/" target="_blank" rel="noopener noreferrer"><img src="https://d2jv02qf7xgjwx.cloudfront.net/customers/4595/images/cropped-logo.png" alt="Khalifa University" width="307" height="66" /></a>
<div class="rb-ku-brand"><span class="rb-ku-brand-name"><bdi>ResearchBee</bdi></span><span class="rb-ku-brand-sub">Khalifa University Library</span></div>
<div class="rb-libguide-toolbar" aria-label="ResearchBee language selector"><div class="model-bar-inner">
<span class="model-label">Language:</span>
<div class="model-toggle">
<button class="lang-btn active" data-lang="english" type="button">EN</button>
<button class="lang-btn" data-lang="arabic" type="button">AR</button>
</div>
<a class="rb-feedback-link" id="rb-feedback-link" href="https://kustar.libwizard.com/f/researchbee" target="_blank" rel="noopener noreferrer">
<svg class="rb-feedback-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 4h14a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9l-6 4V6a2 2 0 0 1 2-2Z"/><path d="M8 10h8M8 14h5"/></svg>
<span>Share feedback</span>
</a>
</div></div>
</div>
</header>
<nav class="rb-ku-nav" aria-label="KU Library links">
<div class="rb-ku-shell rb-ku-nav-inner">
<a href="https://library.ku.ac.ae/lib" target="_blank" rel="noopener noreferrer">KU Library</a>
<a href="https://khazna.ku.ac.ae" target="_blank" rel="noopener noreferrer">Khazna</a>
<a href="https://library.ku.ac.ae/khaznabot" target="_blank" rel="noopener noreferrer">Khazna AI Assistant</a>
<a href="https://library.ku.ac.ae/libbee" target="_blank" rel="noopener noreferrer"><bdi>LibBee</bdi></a>
<a href="https://openpolicyfinder.jisc.ac.uk" target="_blank" rel="noopener noreferrer">Open Policy Finder</a>
</div>
</nav>
<section class="rb-purpose" aria-labelledby="rb-purpose-title">
<div class="rb-purpose-inner">
<div class="rb-purpose-heading">
<p class="rb-purpose-kicker"><bdi>ResearchBee</bdi> &middot; <span>Khalifa University Library</span></p>
<h1 id="rb-purpose-title">Your publication support assistant</h1>
<p class="rb-purpose-tagline">Helping you publish and share your research.</p>
</div>
<div class="rb-purpose-mascot">
<img class="rb-purpose-image" alt="ResearchBee" src="https://d2jv02qf7xgjwx.cloudfront.net/accounts/90850/images/reserachbee.png" width="144" height="144" loading="eager" decoding="async" />
</div>
</div>
<div class="rb-purpose-search">
<div class="rb-purpose-search-inner">
<div class="rb-purpose-search-copy">
<strong>Looking for articles to read?</strong>
<p>ResearchBee is not an article search tool. Use LibBee or Library Primo to find articles.</p>
</div>
<div class="rb-purpose-links">
<a class="rb-purpose-link" href="https://library.ku.ac.ae/libbee" target="_blank" rel="noopener noreferrer"><bdi>LibBee</bdi></a>
<a class="rb-purpose-link" href="https://khalifa.primo.exlibrisgroup.com/discovery/search?vid=971KUOSTAR_INST%3AKU&amp;lang=en" target="_blank" rel="noopener noreferrer">Library Primo</a>
</div>
</div>
</div>
</section>
<div class="rb-workflow-header">
<h2 id="rb-functions-title" tabindex="-1">Choose a function</h2>
<button class="rb-clear-all" id="rb-clear-all" type="button">Clear all &amp; return home</button>
</div>
<div class="tabs-bar">
<div class="tabs-inner">
<button class="tab-btn" data-tab="journals" type="button">
<span class="rb-function-number">1</span>
<span class="tab-label-wrap">
<span class="tab-label-main">Find suitable journals for your article</span>
<span class="tab-label-sub">Identify and compare journals that match your research.</span>
</span>
<svg class="rb-ku-tab-arrow" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
</button>
<button class="tab-btn" data-tab="license" type="button">
<span class="rb-function-number">2</span>
<span class="tab-label-wrap">
<span class="tab-label-main">Check whether you can share your article</span>
<span class="tab-label-sub">Review publisher policies, article versions, licences, and waiting periods before repository deposit.</span>
</span>
<svg class="rb-ku-tab-arrow" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
</button>
<button class="tab-btn" data-tab="data" type="button">
<span class="rb-function-number">3</span>
<span class="tab-label-wrap">
<span class="tab-label-main">Find a research data repository</span>
<span class="tab-label-sub">Explore suitable repositories for storing and sharing your research data.</span>
</span>
<svg class="rb-ku-tab-arrow" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6"/></svg>
</button>
</div>
</div>
<main class="main-content">
<div id="rb-home-view"><p>Select a function above to get started.</p></div>
<aside class="rb-data-notice" id="rb-data-notice" hidden>
<p><strong>Before you submit:</strong> <span>AI assistance uses external services. Do not enter confidential manuscripts or identifiable personal or health data.</span></p>
<details><summary>How your information is used</summary>
<p>Your manuscript, dataset description and chat messages may be sent to OpenAI to provide AI assistance. OpenAlex receives subject keywords to identify suitable journals using related article evidence. Policy checks send journal identifiers or the DOI to the relevant services. Describe sensitive datasets without sharing their contents. Contact KU Library for help with confidential research.</p>
</details>
</aside>
<!-- Tab 1 -->
<div class="tab-panel" id="tab-journals" hidden>
<section class="rb-journal-choices" id="rb-journal-choices" aria-labelledby="rb-journal-choice-title">
<h2 id="rb-journal-choice-title" tabindex="-1">Choose one of two options</h2>
<p class="rb-choice-intro">Start with your research subject or use your manuscript.</p>
<div class="mode-selector">
<button class="mode-btn" data-mode="subject" onclick="window.ResearchBee.switchMode('subject', true)" type="button">
<span class="rb-choice-number">1</span>
<span class="mode-text"><span class="mode-title">Browse by subject</span>
<span class="mode-desc">Enter your research subject to explore and compare suitable journals.</span>
<span class="rb-choice-action">Browse journals by subject</span></span>
</button>
<button class="mode-btn" data-mode="manuscript" onclick="window.ResearchBee.switchMode('manuscript', true)" type="button">
<span class="rb-choice-number">2</span>
<span class="mode-text"><span class="mode-title">Analyse your manuscript</span>
<span class="mode-desc">Enter your title and abstract to find journals that match your manuscript.</span>
<span class="rb-choice-action">Find journals for my manuscript</span></span>
</button>
</div>
</section>
<div class="rb-mode-back" id="rb-mode-back" hidden><button class="rb-back-options" id="rb-back-options" type="button">Back to journal options</button></div>
<div id="mode-subject" hidden>
<form id="subject-form">
<div class="card">
<div class="card-header">
<h2>📊 Browse verified journals by subject</h2>
<p>ResearchBee maps your subject to the closed ASJC/SCImago vocabulary, then recommends only active journal records from the local Scopus/SCImago index. Open Policy Finder checks are available on demand.</p>
</div>
<div class="card-body">
<div class="form-group" style="max-width:620px">
<label for="s-subject" id="lbl-subject">Subject / discipline <span class="req">*</span></label>
<input autocomplete="off" id="s-subject" placeholder="e.g. Artificial Intelligence, Mechanical Engineering, Chemistry" required="" type="text" maxlength="200"/>
<div class="field-hint">Try a specific field such as Computer Science Applications, Library and Information Sciences, Renewable Energy, or Biomedical Engineering.</div>
</div>
<details class="rb-advanced" id="subject-advanced">
<summary>Advanced journal preferences</summary>
<div class="rb-advanced-body form-grid form-2col">
<div class="form-group"><label for="s-ranking-pref">Quartile filter</label><select id="s-ranking-pref"><option>No filter</option><option>Q1</option><option>Q2</option><option>Q1 or Q2</option></select></div>
<div class="form-group"><label for="s-access-pref">Journal access model</label><select id="s-access-pref"><option>Any journal</option><option>Open-access journals</option><option>Diamond / no APC</option></select></div>
<div class="form-group form-full rb-check-field"><label><input id="s-sharing-required" type="checkbox"/> Accepted manuscript must be depositable in a repository</label><div class="field-hint">ResearchBee will check the strongest candidates through Jisc Open Policy Finder. Unknown is not treated as permission or prohibition.</div></div>
<div class="form-group"><label for="s-repo-target">Intended repository</label><select id="s-repo-target"><option>Institutional repository</option><option>Subject repository</option><option>Both institutional &amp; subject</option><option>Not sure</option></select></div>
<div class="form-group"><label for="s-apc">APC budget <span class="rb-planning-only">planning only</span></label><input id="s-apc" placeholder="e.g. no APC or up to USD 2,000" type="text" maxlength="300"/><div class="field-hint">Current title-level fees are not inferred or used as an exclusion unless verified.</div></div>
<div class="form-group"><label for="s-funder">Funder</label><input id="s-funder" placeholder="e.g. ERC, NIH, Wellcome" type="text" maxlength="300"/></div>
<div class="form-group"><label for="s-preferred">Preferred journals</label><textarea id="s-preferred" rows="2" maxlength="500" placeholder="One journal title per line; commas within titles are preserved"></textarea></div>
<div class="form-group form-full"><label for="s-avoid">Journals to exclude</label><textarea id="s-avoid" rows="2" maxlength="500" placeholder="One journal title per line; commas within titles are preserved"></textarea></div>
</div>
</details>
<button class="btn btn-primary" style="max-width:340px;margin-top:16px" type="submit"><span id="btn-subject-submit">Find verified journals</span></button>
</div>
</div>
</form>
<div class="progress-box" id="subject-progress"></div>
<div class="hidden" id="subject-results"></div>
</div>
<div id="mode-manuscript" hidden style="display:none">
<form id="journal-form">
<div class="card">
<div class="card-header">
<h2>📰 Match a manuscript to verified journals</h2>
<p>ResearchBee first classifies the manuscript, then retrieves active journal candidates from the verified index. The AI may explain and rerank those records, but it cannot invent journal identities, ISSNs or metrics.</p>
</div>
<div class="card-body">
<div class="form-grid form-2col">
<div class="form-group form-full"><label for="j-title" id="lbl-title">Title <span class="req">*</span></label><input id="j-title" placeholder="Full manuscript title" required="" type="text" maxlength="300"/></div>
<div class="form-group form-full"><label for="j-abstract" id="lbl-abstract">Abstract <span class="req">*</span></label><textarea id="j-abstract" placeholder="Paste your full abstract here..." required="" rows="7" maxlength="5000"></textarea></div>
<div class="form-group"><label for="j-article-type" id="lbl-article-type">Article type</label><select id="j-article-type"><option>Original research article</option><option>Review article</option><option>Systematic review / meta-analysis</option><option>Short communication</option><option>Case study</option><option>Methods paper</option><option>Perspective / commentary</option><option>Letter</option><option>Conference paper</option></select></div>
</div>
<details class="rb-advanced" id="manuscript-advanced">
<summary>Advanced journal preferences and manuscript context</summary>
<div class="rb-advanced-body form-grid form-2col">
<div class="form-group"><label for="j-keywords" id="lbl-keywords">Keywords</label><input id="j-keywords" placeholder="Comma-separated" type="text" maxlength="500"/></div>
<div class="form-group"><label for="j-discipline" id="lbl-discipline">Discipline / sub-discipline</label><input id="j-discipline" placeholder="e.g. Library and Information Sciences" type="text" maxlength="300"/></div>
<div class="form-group"><label for="j-methods" id="lbl-methods">Methods</label><input id="j-methods" placeholder="e.g. survey, experiment, case study, RAG pipeline" type="text" maxlength="500"/></div>
<div class="form-group"><label for="j-audience" id="lbl-audience">Target audience</label><input id="j-audience" placeholder="e.g. library practitioners, AI researchers" type="text" maxlength="300"/></div>
<div class="form-group"><label for="j-ranking-pref" id="lbl-ranking-pref">Quartile filter</label><select id="j-ranking-pref"><option>No filter</option><option>Q1</option><option>Q2</option><option>Q1 or Q2</option></select></div>
<div class="form-group"><label for="j-access-pref">Journal access model</label><select id="j-access-pref"><option>Any journal</option><option>Open-access journals</option><option>Diamond / no APC</option></select></div>
<div class="form-group form-full rb-check-field"><label><input id="j-sharing-required" type="checkbox"/> Accepted manuscript must be depositable in a repository</label><div class="field-hint">The strongest candidates will be checked through Jisc Open Policy Finder before the shortlist is displayed.</div></div>
<div class="form-group"><label for="j-repo-target" id="lbl-repo-target">Intended repository</label><select id="j-repo-target"><option>Institutional repository</option><option>Subject repository</option><option>Both institutional &amp; subject</option><option>Not sure</option></select></div>
<div class="form-group"><label for="j-apc" id="lbl-apc">APC budget <span class="rb-planning-only">planning only</span></label><input id="j-apc" placeholder="e.g. no APC or up to USD 2,000" type="text" maxlength="300"/><div class="field-hint">Current APCs are not estimated. Unknown fees remain clearly labelled.</div></div>
<div class="form-group"><label for="j-funder" id="lbl-funder">Funder</label><input id="j-funder" placeholder="e.g. ERC, NIH, Wellcome, cOAlition S" type="text" maxlength="300"/></div>
<div class="form-group"><label for="j-institution" id="lbl-institution">Institution</label><input id="j-institution" placeholder="e.g. Khalifa University" type="text" maxlength="300"/></div>
<div class="form-group"><label for="j-country" id="lbl-country">Country / region</label><input id="j-country" placeholder="e.g. UAE" type="text" maxlength="300"/></div>
<div class="form-group form-full"><label for="j-preferred" id="lbl-preferred">Preferred journals</label><textarea id="j-preferred" rows="2" maxlength="500" placeholder="One journal title per line; commas within titles are preserved"></textarea></div>
<div class="form-group form-full"><label for="j-avoid" id="lbl-avoid">Journals to exclude</label><textarea id="j-avoid" rows="2" maxlength="500" placeholder="One journal title per line; commas within titles are preserved"></textarea></div>
</div>
</details>
<button class="btn btn-primary" style="margin-top:16px" type="submit"><span id="btn-journal-submit">Find best-fit verified journals</span></button>
</div>
</div>
</form>
<div class="progress-box" id="journal-progress"></div>
<div class="hidden" id="journal-results"></div>
</div>
</div>
<!-- Tab 2 -->
<div class="tab-panel" id="tab-license" hidden>
<section class="rb-journal-choices" id="rb-share-choices" aria-labelledby="rb-share-choice-title">
<h2 id="rb-share-choice-title" tabindex="-1">How would you like to check sharing permissions?</h2>
<p class="rb-choice-intro">Check a specific article or explore a journal's sharing policy.</p>
<div class="mode-selector">
<button class="rb-choice-btn rb-share-choice" data-share-mode="article" type="button">
<span class="rb-choice-number">1</span><span class="mode-text">
<span class="mode-title">Check a specific article</span>
<span class="mode-desc">Use a DOI or article URL to check sharing permissions and whether your article is in Khazna.</span>
<span class="rb-choice-action">Check my article</span></span></button>
<button class="rb-choice-btn rb-share-choice" data-share-mode="journal" type="button">
<span class="rb-choice-number">2</span><span class="mode-text">
<span class="mode-title">Check a journal's sharing policy</span>
<span class="mode-desc">Use a journal name or ISSN to explore publisher policies on sharing article versions.</span>
<span class="rb-choice-action">Check a journal policy</span></span></button>
</div></section>
<div id="rb-share-work" hidden>
<div class="rb-mode-back"><button class="rb-back-options" id="rb-share-back" type="button">Back to sharing options</button></div>
<form id="license-form">
<div class="card">
<div class="card-header">
<h2 id="rb-share-form-title" tabindex="-1">Check article-sharing permissions</h2>
<p>Review which version you may share, where you may deposit it, and any conditions that apply.</p>
</div>
<div class="card-body">
<div class="form-grid form-2col">
<div class="form-group form-full doi-primary">
<label for="l-doi" id="lbl-l-doi">Article DOI or URL <span class="recommended">recommended — gives a verified answer</span></label>
<input id="l-doi" placeholder="e.g. 10.1080/19322909.2023.2221477 or https://doi.org/..." type="text" maxlength="400"/>
<div class="field-hint">Paste the DOI or the article page URL. We'll extract the DOI automatically and check your exact article — including whether it is already in the KU repository, Khazna.</div>
</div>
</div>
<div id="rb-share-journal-fields" class="form-grid form-2col" hidden>
<div class="form-group"><label for="l-journal" id="lbl-l-journal">Journal name</label><input id="l-journal" placeholder="e.g. Nature Communications" type="text" maxlength="300"/></div>
<div class="form-group"><label for="l-issn" id="lbl-l-issn">ISSN (optional — improves accuracy)</label><input id="l-issn" placeholder="e.g. 2041-1723" type="text" maxlength="20"/></div>
<div class="form-group"><label for="l-publisher" id="lbl-l-publisher">Publisher (optional)</label><input id="l-publisher" placeholder="e.g. Springer Nature" type="text" maxlength="300"/></div>
<div class="form-group form-full"><div class="field-hint">Journal-level results come directly from the Jisc Open Policy Finder API and may contain several conditional options. They do not replace an article-level DOI check.</div></div>
</div>
<details class="rb-advanced" id="rb-sharing-preferences">
<summary>Article version, deposit location and other preferences</summary>
<div class="rb-advanced-body form-grid form-2col">
<div class="form-group"><label for="l-version" id="lbl-l-version">Manuscript version of interest</label><select id="l-version"><option>All versions</option><option>Submitted version / preprint</option><option>Accepted manuscript (AAM / postprint)</option><option>Published version (VoR)</option></select></div>
<div class="form-group"><label for="l-funder" id="lbl-l-funder">Funder (affects rights retention)</label><input id="l-funder" placeholder="e.g. cOAlition S, ERC, NIH, Wellcome" type="text" maxlength="300"/></div>
<div class="form-group"><label for="l-repo" id="lbl-l-repo">Intended deposit location</label><select id="l-repo"><option>Institutional repository</option><option>Subject repository (e.g. arXiv, PMC, SSRN)</option><option>Personal website</option><option>ResearchGate / Academia.edu</option><option>Preprint server</option><option>Both institutional &amp; subject</option></select></div>
<div class="form-group"><label for="l-licence" id="lbl-l-licence">Intended licence</label><select id="l-licence"><option>CC BY</option><option>CC BY-NC</option><option>CC BY-NC-ND</option><option>CC BY-SA</option><option>CC0</option><option>Publisher's bespoke licence</option><option>Not sure</option></select></div>
<div class="form-group form-full"><label for="l-notes" id="lbl-l-notes">Additional context (optional)</label><textarea id="l-notes" placeholder="Already accepted? Already published? Embargo concerns? Funder mandate deadlines?" rows="3" maxlength="500"></textarea></div>
</div>
</details>
<button class="btn btn-primary" style="margin-top:16px" type="submit"><span id="btn-license-submit">Check Green OA policy</span></button>
</div>
</div>
</form>
<div class="progress-box" id="license-progress"></div>
<div class="hidden" id="license-results"></div>
</div>
</div><!-- End sharing workspace -->
<!-- Tab 3 -->
<div class="tab-panel" id="tab-data">
<section id="rb-repo-intro" class="rb-task-choices" aria-labelledby="rb-repo-intro-title">
<h2 id="rb-repo-intro-title">Find a home for your research data</h2>
<p class="rb-choice-intro">Find a suitable repository in two simple steps.</p>
<ol class="rb-repo-step-summary">
<li><span class="rb-choice-number" aria-hidden="true">1</span><div><h3>Describe your dataset</h3><p>Tell us about your data, research field, file formats and approximate size.</p></div></li>
<li><span class="rb-choice-number" aria-hidden="true">2</span><div><h3>Set your sharing requirements</h3><p>Choose access, licence and deposit requirements to find suitable repositories.</p></div></li>
</ol>
<button id="rb-repo-start" class="btn btn-primary" type="button">Start: describe your dataset</button>
</section>
<div class="rb-mode-back" id="rb-repo-back-wrap" hidden><button class="rb-back-options" id="rb-repo-back-options" type="button">Back to data repository overview</button></div>
<form id="repo-form" hidden novalidate>
<div class="card">
<div class="card-header rb-step-header">
<p class="rb-repo-step-label" id="rb-repo-step-label">Step 1 of 2</p>
<h2 id="rb-repo-step-title">Describe your dataset</h2>
<p id="rb-repo-step-description">Enter the basic details so ResearchBee can identify suitable repositories.</p>
</div>
<div class="card-body">
<section id="rb-repo-stage-1" aria-labelledby="rb-repo-step-title">
<div class="form-grid form-2col">
<div class="form-group form-full"><label for="r-title" id="lbl-r-title">Dataset title <span class="req">*</span></label><input id="r-title" placeholder="Descriptive title for your dataset" required="" type="text" maxlength="300"/></div>
<div class="form-group form-full"><label for="r-desc" id="lbl-r-desc">Description <span class="req">*</span></label><textarea id="r-desc" placeholder="What does the dataset contain, how was it collected, and what is its intended reuse?" required="" rows="4" maxlength="2000"></textarea></div>
<div class="form-group"><label for="r-discipline" id="lbl-r-discipline">Discipline / domain <span class="req">*</span></label><input id="r-discipline" placeholder="e.g. genomics, climate science, engineering" required="" type="text" maxlength="300"/></div>
<div class="form-group"><label for="r-datatypes" id="lbl-r-datatypes">Data types <span class="req">*</span></label><input id="r-datatypes" placeholder="e.g. tabular, images, sequencing reads, time series" required="" type="text" maxlength="300"/></div>
<div class="form-group"><label for="r-formats" id="lbl-r-formats">File formats</label><input id="r-formats" placeholder="e.g. CSV, FASTQ, NetCDF, TIFF, HDF5" type="text" maxlength="300"/></div>
<div class="form-group"><label for="r-size" id="lbl-r-size">Approximate total size</label><input id="r-size" placeholder="e.g. 250 MB / 5 GB / 2 TB" type="text" maxlength="300"/></div>
</div>
<div class="rb-repo-step-actions"><button id="rb-repo-next" class="btn btn-primary" type="button">Next: sharing requirements</button></div>
</section>
<section id="rb-repo-stage-2" aria-labelledby="rb-repo-step-title" hidden>
<div class="section-sep">
<div class="section-label">Sensitivity &amp; access</div>
<div class="form-grid form-2col">
<div class="form-group"><label for="r-sensitivity" id="lbl-r-sensitivity">Sensitivity classification</label><select id="r-sensitivity"><option>Open</option><option>Restricted</option><option>Sensitive</option><option>Mixed</option></select></div>
<div class="form-group"><label for="r-personal" id="lbl-r-personal">Contains personal / health data?</label><select id="r-personal"><option>No</option><option>Yes — anonymised</option><option>Yes — pseudonymised</option><option>Yes — identifiable</option><option>Unsure</option></select></div>
<div class="form-group"><label for="r-licence" id="lbl-r-licence">Intended licence</label><select id="r-licence"><option>CC BY</option><option>CC0</option><option>CC BY-NC</option><option>CC BY-SA</option><option>CC BY-NC-SA</option><option>Restricted / custom</option><option>Not sure</option></select></div>
<div class="form-group"><label for="r-embargo" id="lbl-r-embargo">Embargo required?</label><select id="r-embargo"><option>No</option><option value="Yes">Yes</option><option>Unsure</option></select></div>
<div class="form-group"><label for="r-embargo-months">Embargo duration (months, optional)</label><input id="r-embargo-months" type="number" min="1" max="120" step="1" placeholder="e.g. 6 or 12" disabled=""/><div class="field-hint">Enter a duration only when an embargo is required.</div></div>
<div class="form-group"><label for="r-doi" id="lbl-r-doi">Persistent identifier (DOI) required?</label><select id="r-doi"><option>Yes</option><option>No</option><option>Unsure</option></select></div>
<div class="form-group"><label for="r-versioning" id="lbl-r-versioning">Versioning required?</label><select id="r-versioning"><option>Yes</option><option>No</option><option>Unsure</option></select></div>
</div>
</div>
<div class="section-sep">
<div class="section-label">Context</div>
<div class="form-grid form-2col">
<div class="form-group"><label for="r-funder" id="lbl-r-funder">Funder</label><input id="r-funder" placeholder="e.g. Horizon Europe, NIH, ERC, ADEK" type="text" maxlength="300"/></div>
<div class="form-group"><label for="r-institution" id="lbl-r-institution">Institution</label><input id="r-institution" placeholder="e.g. Khalifa University" type="text" maxlength="300"/></div>
<div class="form-group"><label for="r-country" id="lbl-r-country">Country / region</label><input id="r-country" placeholder="e.g. UAE" type="text" maxlength="300"/></div>
<div class="form-group"><label for="r-preferred" id="lbl-r-preferred">Preferred / required repository (optional)</label><input id="r-preferred" placeholder="e.g. Zenodo, GenBank" type="text" maxlength="300"/></div>
<div class="form-group form-full"><label for="r-publication" id="lbl-r-publication">Linked publication / DOI (optional)</label><input id="r-publication" placeholder="Related article DOI or title" type="text" maxlength="300"/></div>
<div class="form-group form-full"><label for="r-notes" id="lbl-r-notes">Additional notes</label><textarea id="r-notes" placeholder="Any special requirements, funder mandates, or context..." rows="3" maxlength="500"></textarea></div>
</div>
</div>
<div class="rb-repo-step-actions"><button id="rb-repo-previous" class="rb-back-options" type="button">Back to dataset details</button>
<button class="btn btn-primary" style="margin-top:8px" type="submit"><span id="btn-repo-submit">Find best repositories</span></button>
</div>
</section>
</div>
</div>
</form>
<div class="progress-box" id="repo-progress"></div>
<div class="hidden" id="repo-results"></div>
</div>
</main>
<div class="site-footer rb-app-footer">
<div class="footer-inner">
<p>Ranking metrics sourced from journal data (2025). Always verify policies on <a href="https://openpolicyfinder.jisc.ac.uk" rel="noopener noreferrer" target="_blank">Open Policy Finder</a> and repositories on <a href="https://www.re3data.org" rel="noopener noreferrer" target="_blank">re3data</a> before deposit.</p>
<p><a href="https://library.ku.ac.ae/lib" rel="noopener noreferrer" target="_blank">KU Library</a> · <a href="https://khazna.ku.ac.ae" rel="noopener noreferrer" target="_blank">KU repository — Khazna</a> · <a href="https://github.com/ku-library/researchbee" rel="noopener noreferrer" target="_blank">GitHub</a> <span class="rb-version-badge">Interface v1.9.3</span></p>
<p class="footer-sources">
<strong>Data sources.</strong>
Self-archiving permissions: <a href="https://shareyourpaper.org/permissions" rel="noopener noreferrer" target="_blank">Shareyourpaper.org Permissions</a> (OA.Works).
Journal metrics: SCImago, (n.d.). <a href="https://www.scimagojr.com" rel="noopener noreferrer" target="_blank">SJR — SCImago Journal &amp; Country Rank</a> [Portal], data used under non-commercial terms with attribution.
Journal and works metadata: <a href="https://openalex.org" rel="noopener noreferrer" target="_blank">OpenAlex</a>.
Journal-level self-archiving policies: <a href="https://openpolicyfinder.jisc.ac.uk" rel="noopener noreferrer" target="_blank">Jisc Open Policy Finder</a>, licensed CC BY-NC-ND 4.0.
Repository holdings: <a href="https://khazna.ku.ac.ae" rel="noopener noreferrer" target="_blank">Khazna</a> (OAI-PMH).
ResearchBee reports what these sources say; where a source cannot confirm a policy, it says so rather than estimating.
</p>
</div>
</div>
<button aria-label="Need help? Chat with ResearchBee" id="rb-mobile-chat-bar">
<img alt="ResearchBee" class="rb-mobile-bar-icon rb-chat-mascot-icon" data-rb-mascot="" src="https://d2jv02qf7xgjwx.cloudfront.net/accounts/90850/images/reserachbee.png" width="44" height="44" loading="lazy" decoding="async" />
<span class="rb-mobile-bar-text">
<span class="rb-mobile-bar-top">Need help?</span>
<span class="rb-mobile-bar-main">Chat with ResearchBee</span>
</span>
<span class="rb-mobile-bar-arrow">›</span>
</button>
<div id="rb-chat-tooltip">&#128172; Ask ResearchBee about publishing and RDM</div>
<button aria-label="Open ResearchBee chat — Need help? Chat with ResearchBee" id="rb-chat-launcher">
<img alt="ResearchBee" class="rb-launcher-icon rb-chat-mascot-icon" data-rb-mascot="" src="https://d2jv02qf7xgjwx.cloudfront.net/accounts/90850/images/reserachbee.png" width="44" height="44" loading="lazy" decoding="async" />
<span class="rb-launcher-label">
<span class="rb-launcher-label-top">Need help?</span>
<span class="rb-launcher-label-main">Chat with ResearchBee</span>
</span>
<span id="rb-chat-badge"></span>
</button>
<div aria-hidden="true" aria-label="ResearchBee chat assistant" id="rb-chat-panel" role="dialog">
<div class="rb-chat-header">
<img alt="ResearchBee" data-rb-mascot="" src="https://d2jv02qf7xgjwx.cloudfront.net/accounts/90850/images/reserachbee.png" width="44" height="44" loading="lazy" decoding="async" />
<div class="rb-chat-header-text">
<span class="rb-chat-header-name">ResearchBee</span>
<span class="rb-chat-header-sub">KU Library Publishing Assistant</span>
</div>
<div class="rb-chat-status" title="Chat availability is checked when you send a message" aria-hidden="true"></div>
<button aria-label="Close chat" class="rb-chat-close" id="rb-chat-close" type="button">×</button>
</div>
<div class="rb-chat-disclaimer">
<span>Chat messages are sent to OpenAI. Do not share confidential or personal data.</span><br/>
⚠️ Always verify OA policies on
<a href="https://openpolicyfinder.jisc.ac.uk" rel="noopener noreferrer" style="color:#92400E;font-weight:600;margin-left:3px" target="_blank">Open Policy Finder</a>
</div>
<div aria-live="polite" id="rb-chat-messages"></div>
<div class="rb-chat-input-wrap">
<textarea aria-label="Chat message" id="rb-chat-input" maxlength="2000" placeholder="Ask about KU OA policy, publishing rights, or Khazna…" rows="1"></textarea>
<button aria-label="Send message" disabled="" id="rb-chat-send" type="button">
<svg fill="none" height="16" viewbox="0 0 16 16" width="16"><path d="M14.5 8L2 2l2.5 6L2 14l12.5-6z" fill="white"></path></svg>
</button>
</div>
<div class="rb-chat-footer">ResearchBee · <a href="https://library.ku.ac.ae/lib" rel="noopener noreferrer" target="_blank">KU Library</a></div>
</div>
<noscript><div class="rb-libguide-noscript">ResearchBee requires JavaScript. Please enable JavaScript and reload this page.</div></noscript>
</div>
<script>
(function () {
"use strict";
const RB_ROOT = document.getElementById("researchbee-app");
if (!RB_ROOT || RB_ROOT.dataset.researchbeeInitialized === "true") return;
RB_ROOT.dataset.researchbeeInitialized = "true";
window.ResearchBee = window.ResearchBee || {};
// api.js - fetch wrapper for Research Navigator backend
// Set RB_API_BASE to your HuggingFace Space URL before deploying
const RB_API_BASE = "https://nikeshn-researchbee.hf.space";
const RB_REQUESTS = new Map();
// Include unkeyed enrichment/export calls in a full-session reset.
const RB_ACTIVE_REQUESTS = new Set();
let RB_SESSION_GENERATION = 0;
function rbCancelAllRequests() {
RB_SESSION_GENERATION += 1;
RB_ACTIVE_REQUESTS.forEach(request => {
request.superseded = true;
request.controller.abort();
});
RB_ACTIVE_REQUESTS.clear();
RB_REQUESTS.clear();
}
function rbApiError(body, status) {
const detail = body?.detail ?? body?.error ?? body?.message;
if (Array.isArray(detail)) {
return detail.map(item => {
const field = Array.isArray(item.loc) ? item.loc.filter(part => !["body", "manuscript", "dataset", "license_input"].includes(part)).join(" → ") : "Input";
return `${field}: ${item.msg || "Please check this value."}`;
}).join("; ");
}
return typeof detail === "string" && detail ? detail : `Request failed (HTTP ${status}). Please try again.`;
}
function rbWaitText(english, arabic) { return getLanguage() === "arabic" ? arabic : english; }
function rbCancelRequest(key, userCancelled = false) {
const previous = RB_REQUESTS.get(key);
if (previous) { previous.cancelled = userCancelled; previous.superseded = !userCancelled; previous.controller.abort(); RB_REQUESTS.delete(key); }
}
function rbStaleRequest(error) { return Boolean(error?.stale); }
async function rbFetchJson(url, options = {}, settings = {}) {
const key = settings.requestKey || "";
if (key) rbCancelRequest(key);
const request = { controller: new AbortController(), superseded: false, timedOut: false, cancelled: false, session: RB_SESSION_GENERATION };
RB_ACTIVE_REQUESTS.add(request);
if (key) RB_REQUESTS.set(key, request);
const timer = setTimeout(() => { request.timedOut = true; request.controller.abort(); }, settings.timeoutMs || 120000);
try {
const response = await fetch(url, { ...options, signal: request.controller.signal });
let data;
try { data = await response.json(); }
catch (error) {
if (request.controller.signal.aborted) throw error;
if (response.ok) throw new Error("The service returned an unreadable response. Please try again.");
data = {};
}
if (request.controller.signal.aborted) throw Object.assign(new Error("Request cancelled."), { name: "AbortError" });
if (request.superseded || request.session !== RB_SESSION_GENERATION) throw Object.assign(new Error("A newer request replaced this search."), { stale: true });
if (!response.ok) throw new Error(rbApiError(data, response.status));
return data;
} catch (error) {
if (request.superseded || request.session !== RB_SESSION_GENERATION) throw Object.assign(new Error("A newer request replaced this search."), { stale: true });
if (request.cancelled) throw Object.assign(new Error(rbWaitText("Stopped waiting. Your entries are preserved. You can try again.", "تم إيقاف الانتظار. تم الاحتفاظ بمدخلاتك ويمكنك المحاولة مرة أخرى.")), { cancelled: true });
if (request.timedOut) throw new Error(rbWaitText("The request timed out. Please try again; the service may be starting up or busy. Your entries are preserved.", "انتهت مهلة الطلب. يرجى المحاولة مرة أخرى؛ قد تكون الخدمة قيد التشغيل أو مشغولة. تم الاحتفاظ بمدخلاتك."));
if (error instanceof TypeError) throw new Error(rbWaitText("Could not reach ResearchBee. Check your connection and try again. Your entries are preserved.", "تعذر الاتصال بـ ResearchBee. تحقق من اتصالك ثم حاول مرة أخرى. تم الاحتفاظ بمدخلاتك."));
throw error;
} finally {
clearTimeout(timer);
RB_ACTIVE_REQUESTS.delete(request);
if (key && RB_REQUESTS.get(key) === request) RB_REQUESTS.delete(key);
}
}
async function callAPI(endpoint, payload, settings = {}) {
return rbFetchJson(`${RB_API_BASE}${endpoint}`, {
method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload),
}, settings);
}
function rbRenderChatText(container, value, streaming = false) {
const fragment = document.createDocumentFragment();
const lines = String(value || "").split("\n");
lines.forEach((line, index) => {
if (index) fragment.appendChild(document.createElement("br"));
const matches = line.matchAll(/https?:\/\/[^\s<>"']+/g);
let offset = 0;
for (const match of matches) {
fragment.appendChild(document.createTextNode(line.slice(offset, match.index)));
const safe = safeHttpsUrl(match[0]);
if (safe) {
const link = document.createElement("a");
link.href = safe; link.target = "_blank"; link.rel = "noopener noreferrer";
link.textContent = match[0]; fragment.appendChild(link);
} else fragment.appendChild(document.createTextNode(match[0]));
offset = match.index + match[0].length;
}
fragment.appendChild(document.createTextNode(line.slice(offset)));
});
if (streaming) { const cursor = document.createElement("span"); cursor.className = "rb-cursor"; cursor.textContent = "▌"; cursor.setAttribute("aria-hidden", "true"); fragment.appendChild(cursor); }
container.replaceChildren(fragment);
}
function rbPrepareChatHistory(messages) {
return messages.slice(-20).map(message => ({ role: message.role, content: String(message.content || "").slice(0, message.role === "assistant" ? 12000 : 2000) }));
}
function rbOpenAlexId(value, prefix = "S") {
let candidate = String(value || "").trim();
if (/^https:\/\//i.test(candidate)) {
try { const url = new URL(candidate); if (url.hostname !== "openalex.org") return ""; candidate = url.pathname.split("/").filter(Boolean).pop() || ""; } catch (_) { return ""; }
}
const match = candidate.match(new RegExp(`^${prefix}?(\\d+)$`, "i"));
return match ? `${prefix}${match[1]}` : "";
}
function getModel() {
return RB_ROOT.querySelector(".model-btn.active")?.dataset.model || "gpt-4o-mini";
}
function getLanguage() {
return RB_ROOT.querySelector(".lang-btn.active")?.dataset.lang || "english";
}
// Release A: keep untrusted values in JavaScript memory rather than embedding
// them inside inline event-handler attributes.
const RB_COVER_LETTER_PAYLOADS = new Map();
const RB_RELATED_WORK_PAYLOADS = new Map();
const RB_SUBJECT_JOURNAL_PAYLOADS = new Map();
function rbDomKey(value, fallback = "item") {
const clean = String(value || "").replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 40);
return clean || fallback;
}
function safeHttpsUrl(value, allowedHosts = []) {
try {
const text = String(value || "").trim();
if (!/^https:\/\//i.test(text)) return "";
const url = new URL(text);
if (url.protocol !== "https:" || url.username || url.password || (url.port && url.port !== "443")) return "";
if (!url.hostname.includes(".") || /^(localhost|127\.|10\.|192\.168\.|169\.254\.|0\.)/.test(url.hostname) || /^172\.(1[6-9]|2\d|3[01])\./.test(url.hostname) || url.hostname.includes(":") || /\.(local|internal|localhost)$/.test(url.hostname)) return "";
if (allowedHosts.length && !allowedHosts.some(host =>
url.hostname === host || url.hostname.endsWith(`.${host}`)
)) return "";
return url.href;
} catch (_) {
return "";
}
}
function makeExternalLink(url, label, allowedHosts = []) {
const safeUrl = safeHttpsUrl(url, allowedHosts);
if (!safeUrl) return null;
const link = document.createElement("a");
link.href = safeUrl;
link.target = "_blank";
link.rel = "noopener noreferrer";
link.className = "vlink";
link.style.fontSize = "11px";
link.textContent = label;
return link;
}
function setInlineMessage(container, message, kind = "muted") {
if (!container) return;
const p = document.createElement("p");
p.style.fontSize = "13px";
p.style.padding = "8px";
p.style.color = kind === "error" ? "var(--danger)" :
kind === "success" ? "var(--success)" : "var(--text-muted)";
p.textContent = message;
container.replaceChildren(p);
}
/* ------------------------------------------------------------------ */
// render.js - shared rendering helpers
const MASCOT = "https://d2jv02qf7xgjwx.cloudfront.net/accounts/90850/images/reserachbee.png";
const _HF = "https://nikeshn-researchbee.hf.space";
function renderMascotRow(message) {
return `
<div class="results-mascot-row">
<img src="${MASCOT}" class="results-mascot-img" alt="ResearchBee" width="44" height="44" loading="lazy" decoding="async">
<div class="results-mascot-bubble">${message}</div>
</div>`;
}
function esc(str) {
if (!str) return "";
return String(str)
.replace(/&/g, "&amp;").replace(/</g, "&lt;")
.replace(/>/g, "&gt;").replace(/"/g, "&quot;");
}
// Evidence-backed links; publisher discovery is strictly click-triggered.
function rbTrustedAnchor(url, label, cls = "") {
const safe = safeHttpsUrl(url);
return safe ? `<a href="${esc(safe)}" target="_blank" rel="noopener noreferrer" class="${esc(cls)}">${esc(label)}</a>` : esc(label);
}
function rbJournalTitle(journal) {
return rbTrustedAnchor(journal.journal_links?.homepage?.url, journal.name || "");
}
function rbLinkStatus(link) {
if (!link?.url) return esc(rbText("Not available"));
const status = rbText(({"metadata-only":"Metadata only",checked:"Checked",curated:"Curated"})[link.status] || "Not available");
const date = link.reviewed_at || link.source_updated_at;
return `${esc(status)}${date ? ` · ${esc(date)}` : ""}${link.source ? ` · ${rbTrustedAnchor(link.source, rbText("Source"))}` : ""}`;
}
function rbJournalLinks(journal) {
const links = journal.journal_links || {};
const home = links.homepage || {}, guide = links.guidelines || {};
const key = String(links.canonical_id || journal.scopus_id || journal.id || journal.issn || "");
return `<div class="rb-trusted-links" data-link-key="${esc(key)}" aria-live="polite">
<div>${home.url ? rbTrustedAnchor(home.url, rbText("Journal website"), "btn btn-ghost") : `<strong>${esc(rbText("Journal website"))}: ${esc(rbText("Not available"))}</strong>`}
<small>${rbLinkStatus(home)}</small></div>
<div>${guide.url ? rbTrustedAnchor(guide.url, rbText("Author guidelines"), "btn btn-ghost") : `<strong>${esc(rbText("Author guidelines"))}: ${esc(rbText("Not available"))}</strong>`}
<small>${rbLinkStatus(guide)}${guide.scope ? ` · ${esc(rbText(guide.scope === "journal-specific" ? "Journal-specific instructions" : "General publisher guidance"))}` : ""}</small></div>
${!guide.url && links.can_discover ? `<button type="button" class="btn btn-ghost rb-find-guidelines" data-canonical-id="${esc(links.canonical_id)}">${esc(rbText("Find author guidelines"))}</button>` : ""}
${guide.attempted_at && !guide.url ? `<small>${esc(rbText("Author guidance unavailable; use the journal website if available."))} · ${esc(guide.attempted_at)}</small>` : ""}
</div>`;
}
function rbCategoryRows(journal) { return renderFieldQuartiles(journal.quartiles_by_field || []); }
async function rbFindGuidelines(event) {
const button = event.target.closest?.(".rb-find-guidelines");
if (!button || button.disabled) return;
const host = button.closest(".rb-trusted-links");
const generation = RB_DISCOVERY_STATE.generation;
const session = RB_SESSION_GENERATION;
button.disabled = true;
button.textContent = rbText("Checking official publisher page…");
try {
const links = await callAPI("/api/journal-links", { scopus_id: button.dataset.canonicalId }, { timeoutMs: 30000 });
if (generation !== RB_DISCOVERY_STATE.generation || session !== RB_SESSION_GENERATION || !host.isConnected) return;
RB_DISCOVERY_STATE.all.forEach(j => { if (String(j.journal_links?.canonical_id) === button.dataset.canonicalId) j.journal_links = links; });
RB_ROOT.querySelectorAll(".rb-trusted-links").forEach(node => {
if (node.dataset.linkKey === host.dataset.linkKey) node.outerHTML = rbJournalLinks({journal_links:links});
});
} catch (error) {
if (rbStaleRequest(error) || generation !== RB_DISCOVERY_STATE.generation || session !== RB_SESSION_GENERATION || !host.isConnected) return;
button.disabled = false; button.textContent = rbText("Find author guidelines");
const note = document.createElement("small"); note.textContent = rbText("The lookup failed. The journal website remains available; try again later."); host.append(note);
}
}
RB_ROOT.addEventListener("click", rbFindGuidelines);
function quartileBadge(q) {
if (!q || q === "-") return "";
const cls = { Q1: "b-q1", Q2: "b-q2", Q3: "b-q3", Q4: "b-q4" }[q] || "b-muted";
return `<span class="badge ${cls}">${esc(q)}</span>`;
}
function confidenceBadge(c) {
const cls = { High: "b-success", Medium: "b-warning", Low: "b-muted" }[c] || "b-muted";
return `<span class="badge ${cls}">Fit: ${esc(c)}</span>`;
}
function oaStatusBadge(s) {
const cls = s === "Confirmed" ? "b-success"
: s === "Partially confirmed" ? "b-warning" : "b-danger";
return `<span class="badge ${cls}">OA: ${esc(s)}</span>`;
}
function accessBadge(a) {
const cls = a === "Open" ? "b-success" : a === "Controlled" ? "b-danger" : "b-warning";
return `<span class="badge ${cls}">${esc(a)}</span>`;
}
function fairBadge(f) {
const cls = f === "High" ? "b-success" : f === "Medium" ? "b-warning" : "b-muted";
return `<span class="badge ${cls}">FAIR: ${esc(f)}</span>`;
}
function allowedClass(a) {
if (a === "Yes") return "v-yes";
if (a === "No") return "v-no";
if (a === "Conditional") return "v-conditional";
if (a === "No policy listed") return "v-none";
return "v-unclear";
}
function renderVersionBlock(title, v) {
if (!v) return "";
const options = Array.isArray(v.options) ? v.options : [];
const optionsHtml = options.length ? `
<details class="opf-options">
<summary>${options.length} Open Policy Finder option${options.length === 1 ? "" : "s"} — view details</summary>
<ol class="opf-option-list">
${options.map((option, index) => `
<li class="opf-option-item">
<div class="opf-option-summary">Option ${index + 1}: ${esc(option.summary || "Policy option")}</div>
<div class="opf-option-meta">
${option.where ? `<div><strong>Where:</strong> ${esc(option.where)}</div>` : ""}
${option.embargo ? `<div><strong>Embargo:</strong> ${esc(option.embargo)}</div>` : ""}
${option.licence ? `<div><strong>Licence:</strong> ${esc(option.licence)}</div>` : ""}
${option.conditions ? `<div><strong>Conditions:</strong> ${esc(option.conditions)}</div>` : ""}
</div>
</li>`).join("")}
</ol>
</details>` : "";
return `
<div class="version-card">
<div class="v-head">
<span class="v-title">${esc(title)}</span>
<span class="v-allowed ${allowedClass(v.allowed)}">${esc(v.allowed || "Unclear")}</span>
</div>
<dl class="v-grid">
${v.where ? `<div><dt>Where</dt><dd>${esc(v.where)}</dd></div>` : ""}
${v.embargo ? `<div><dt>Embargo</dt><dd>${esc(v.embargo)}</dd></div>` : ""}
${v.licence ? `<div><dt>Licence</dt><dd>${esc(v.licence)}</dd></div>` : ""}
${v.conditions ? `<div class="v-full"><dt>Conditions</dt><dd>${esc(v.conditions)}</dd></div>` : ""}
</dl>
${optionsHtml}
</div>`;
}
function renderVerifyLinks(vl, showScopusPrimary = true) {
if (!vl) return "";
const values = showScopusPrimary
? [["Scopus", vl.scopus], ["Open Policy Finder", vl.sherpa_romeo], ["DOAJ", vl.doaj], ["OpenAlex", vl.openalex]]
: [["Open Policy Finder", vl.sherpa_romeo], ["Scopus", vl.scopus], ["DOAJ", vl.doaj], ["OpenAlex", vl.openalex]];
const links = values.map(([label, value]) => [label, safeHttpsUrl(value)]).filter(([, url]) => url);
if (!links.length) return "";
return `<div class="verify-row"><span class="verify-lbl">${esc(rbText("Verify on:"))}</span>${links.map(([label, url]) => `<a href="${esc(url)}" target="_blank" rel="noopener noreferrer" class="vlink ${label === "Scopus" && showScopusPrimary ? "vlink-scopus" : ""}">${esc(label)}</a>`).join("")}</div>`;
}
function renderOpenAlexMetrics(oa) {
if (!oa) return "";
const fmt = (n) => n != null ? Number(n).toLocaleString() : "-";
const tags = [oa.is_in_doaj ? "· DOAJ-listed" : "", oa.is_oa ? "· OA journal" : ""].filter(Boolean).join(" ");
return `
<dl class="oa-metrics">
<div class="oa-m"><dt>Works</dt><dd>${fmt(oa.works_count)}</dd></div>
<div class="oa-m"><dt>Citations</dt><dd>${fmt(oa.cited_by_count)}</dd></div>
<div class="oa-m"><dt>h-index</dt><dd>${fmt(oa.h_index)}</dd></div>
<div class="oa-m"><dt>2-yr citedness</dt><dd>${oa.two_yr_mean_citedness != null ? Number(oa.two_yr_mean_citedness).toFixed(2) : "-"}</dd></div>
<div class="oa-src">Source: OpenAlex ${tags}</div>
</dl>`;
}
/* =========================================================================
Scopus / SCImago index display layer (journals.db, 48,888 titles)
The backend has been returning these fields since the index went in and the
page has never drawn them:
quartiles_by_field the headline quartile is the journal's BEST across its
subject areas; 46% of ranked journals rank differently
across their own fields
indexation_state "no quartile" is not one answer, it is six
successor_title ~7,000 renamed titles — redirect, don't warn
oa_diamond no APC and no subscription
Every function here returns "" when the fields are absent, so the ~700
titles still served by the SCImago CSV fallback degrade to exactly what the
page rendered before.
========================================================================= */
/* Two backend paths produce the extras and they land in two different places:
enrich_ranking() -> j.ranking.* (the analysed shortlist cards)
enrich_extended() -> j.* (the quick-match table rows)
Read both. Neither is guaranteed. */
function idxFields(j) {
const r = (j && j.ranking) || {};
const pick = (k) => (j && j[k] !== undefined && j[k] !== null ? j[k] : r[k]);
return {
byField: pick("quartiles_by_field") || [],
state: pick("indexation_state") || "",
message: pick("indexation_message") || "",
warn: pick("warn") === true,
indexed: pick("currently_indexed"),
successor: pick("successor_title") || "",
diamond: pick("oa_diamond") === true,
sjr: pick("sjr"),
fromScopus: pick("from_scopus"),
};
}
const RB_Q_CLASS = { Q1: "b-q1", Q2: "b-q2", Q3: "b-q3", Q4: "b-q4" };
function diamondBadge(j) {
return idxFields(j).diamond
? `<span class="badge b-diamond" title="No article-processing charge for authors and no subscription fee for readers.">◆ Diamond OA</span>`
: "";
}
/* Show the spread only when there is a spread to show. For a single-field
journal the headline quartile already says everything, and a block that
repeats it is noise on the common case. */
function renderFieldQuartiles(byField) {
if (!Array.isArray(byField) || !byField.length) return `<p>SCImago SJR · ${esc(rbText("Not available"))}</p>`;
const chips = byField.map(f => `<span class="fq-chip">
${f.profile_url && /^Q[1-4]$/.test(f.quartile || "") ? `<a href="${esc(safeHttpsUrl(f.profile_url, ["scimagojr.com"]))}" target="_blank" rel="noopener noreferrer">${quartileBadge(f.quartile)}</a>` : esc(rbText("Not available"))}
<span class="fq-field">${rbTrustedAnchor(safeHttpsUrl(f.category_url,["scimagojr.com"]), f.field)}${!f.category_url ? ` · ${esc(rbText("Not available"))}` : ""}</span>
<small>${esc(f.source || rbText("Not available"))} · ${esc(f.year || rbText("Not available"))}</small></span>`).join("");
return `<div class="fq-block"><div class="fq-label">${esc(rbText("Quartile by field"))}</div><div class="fq-chips">${chips}</div><p class="fq-note">${esc(rbText("Each quartile belongs to its own category. SCImago SJR is separate from Scopus CiteScore."))}</p></div>`;
}
/* A journal too new for an SJR is a timing artefact and safe to submit to; a
journal Scopus discontinued is the opposite. A blank quartile field says
neither. The prose comes from the API (`indexation_message`) rather than
from here, so the wording — including Scopus's caveat that discontinuation
is not evidence of predatory practice — has one source of truth. */
const RB_IDX_UI = {
discontinued: { cls: "idx-danger", icon: "⚠", short: "Discontinued", head: "Discontinued by Scopus" },
renamed: { cls: "idx-info", icon: "↻", short: "Renamed", head: "No longer indexed under this name" },
ceased: { cls: "idx-muted", icon: "◻", short: "Ceased", head: "No longer indexed — the journal appears to have ceased" },
not_indexed: { cls: "idx-muted", icon: "◻", short: "Not in Scopus",head: "No Scopus source record" },
indexed_new: { cls: "idx-info", icon: "⏳", short: "Too new", head: "Indexed in Scopus — quartile not yet assigned" },
indexed_unranked: { cls: "idx-muted", icon: "—", short: "Unranked", head: "Indexed in Scopus — SCImago computes no SJR" },
indexed_no_sjr: { cls: "idx-muted", icon: "—", short: "No SJR", head: "Indexed in Scopus — absent from SCImago" },
// indexed_ranked is deliberately absent: the metrics block already says it.
};
function renderIndexationNotice(j) {
const f = idxFields(j);
if (!f.state || f.state === "indexed_ranked") return "";
const ui = RB_IDX_UI[f.state];
if (!ui) return "";
// A successor is a redirect, not a verdict. On a renamed title it is the
// answer; on a discontinued one it only says where to look next, and must
// not be allowed to read as reassurance.
const successor = f.successor
? `
<p class="idx-successor">Continues as <strong>${esc(f.successor)}</strong><a href="https://www.scimagojr.com/journalsearch.php?q=${encodeURIComponent(f.successor)}" target="_blank" rel="noopener">look it up ↗</a></p>`
: "";
return `
<div class="idx-notice ${ui.cls}">
<div class="idx-head"><span class="idx-icon">${ui.icon}</span>${esc(ui.head)}</div>
${f.message ? `<p class="idx-msg">${esc(f.message)}</p>` : ""}${successor}
</div>`;
}
/* Compact form for the quick-match table, where there is no room for a notice
block and the quartile column otherwise renders a bare "-". */
function indexationFlag(j) {
const f = idxFields(j);
if (!f.state || f.state === "indexed_ranked") return "";
const ui = RB_IDX_UI[f.state];
if (!ui) return "";
return `<span class="ext-flag ${ui.cls}" title="${esc(ui.head)}${f.message ? " — " + esc(f.message) : ""}">${esc(ui.short)}</span>`;
}
/* Silence about where an answer came from is how an interface makes itself
look more certain than it is. When journals.db had no Scopus source record
and the SCImago CSV served the lookup, say so — otherwise the ABSENCE of an
indexation notice reads as "checked, nothing to report" when it is really
"not checked". */
function renderIndexProvenance(j) {
const f = idxFields(j);
if (f.fromScopus !== false) return "";
return `
<p class="rank-verify rank-fallback"><strong>Source:</strong> matched against the SCImago list only — there is no Scopus source record for this title, so its indexation state and per-field quartiles could not be checked.</p>`;
}
/* Signature is (r, j): the journal object is needed because enrich_extended()
puts the extras at the top level rather than under .ranking. Called with one
argument it still works, it just cannot see that variant. */
function renderRankingBlock(r, j) {
if (!r) return "";
const host = j || { ranking: r };
const f = idxFields(host);
const isConfirmed = r.verification_status === "Confirmed";
const isDerived = /openalex-derived/i.test(r.verification_status || "");
const cls = isConfirmed ? "confirmed" : isDerived ? "derived" : "unverified";
const badge = isConfirmed
? `<span class="badge b-success">✓ Verified by ISSN</span>`
: isDerived
? `<span class="badge b-warning">[!] OpenAlex-derived</span>`
: `<span class="badge b-danger">[!] Unverified — check manually</span>`;
return `
<div class="rank-box ${cls}">
<div class="rank-head">
<h5>📊 Journal metrics</h5>
${badge}
</div>
<dl class="rank-grid">
<div class="rank-item"><dt>Source</dt><dd>${esc(r.source || rbText("Not available"))}</dd></div>
<div class="rank-item"><dt>Year</dt><dd>${esc(r.year || rbText("Not available"))}</dd></div>
<div class="rank-item"><dt>Quartile</dt><dd>${r.quartile ? `<span class="badge ${RB_Q_CLASS[r.quartile] || "b-muted"}">${esc(r.quartile)}</span>` : "-"}</dd></div>
${r.percentile ? `<div class="rank-item"><dt>Rank/Percentile</dt><dd>${esc(r.percentile)}</dd></div>` : ""}
${f.sjr != null ? `<div class="rank-item"><dt>SJR</dt><dd>${esc(String(f.sjr))}</dd></div>` : ""}
${r.category ? `<div class="rank-item"><dt>Category</dt><dd style="font-size:11px">${esc(r.category)}</dd></div>` : ""}
${r.h_index ? `<div class="rank-item"><dt>h-index</dt><dd>${esc(r.h_index)}</dd></div>` : ""}
</dl>
${renderFieldQuartiles(f.byField)}
${r.interpretation ? `<p class="rank-note">${esc(r.interpretation)}</p>` : ""}
${r.verification_status ? `<p class="rank-verify"><strong>Verification:</strong> ${esc(r.verification_status)}</p>` : ""}${renderIndexProvenance(host)}
</div>`;
}
function renderKhaznaCard(k, mode = "article") {
const tip = mode === "data"
? "Even when your data lives in a domain-specific repository, register the metadata in the KU repository, Khazna, so the work appears in KU's research portfolio."
: "Register your publication with Khazna. Deposit a manuscript file only when the checked version, repository location, licence and embargo conditions permit it; contact KU Library when permission is unclear.";
return `
<div class="khazna-card">
<div class="khazna-head">
<span style="font-size:22px">🏛️</span>
<div>
<h3>KU repository &mdash; Khazna</h3>
<div style="font-size:12px;opacity:.8">khazna.ku.ac.ae</div>
</div>
</div>
<div class="khazna-body">
<p>${esc(rbText(k.message || tip))}</p>
<div class="khazna-tip"><span>💡</span><span>${esc(rbText(tip))}</span></div>
<div class="khazna-actions">
<a href="${esc(safeHttpsUrl(k.url || "https://khazna.ku.ac.ae"))}" target="_blank" class="k-btn k-btn-fill">🔗 Visit Khazna</a>
<a href="mailto:${esc(k.contact || "khazna@ku.ac.ae")}" class="k-btn k-btn-outline">✉ khazna@ku.ac.ae</a>
<a href="${esc(safeHttpsUrl(k.library_url || "https://library.ku.ac.ae/lib"))}" target="_blank" class="k-btn k-btn-outline">📚 KU Library</a>
</div>
</div>
</div>`;
}
function renderHelpCard() {
return `
<div class="help-card">
<div class="help-left">
<span class="help-icon">📚</span>
<div class="help-text">
<h4>Need help? Contact KU Library</h4>
<p>Not sure what to deposit, which version, or how? Our librarians can advise on open access, self-archiving, and research data management.</p>
</div>
</div>
<div class="help-links">
<a href="mailto:library@ku.ac.ae" class="k-btn k-btn-fill" style="font-size:12px;padding:7px 14px">✉ Contact Library</a>
<a href="https://library.ku.ac.ae/lib" target="_blank" class="k-btn k-btn-outline" style="font-size:12px;padding:7px 14px">🔗 Library Website</a>
</div>
</div>`;
}
function rbRenderRepositoryConstraints(repository) {
const assessment = repository.constraint_assessment || {};
const metadataOnly = repository.metadata_registration_only === true || assessment.state === "metadata_only";
const restricted = repository.file_deposit_recommended === false || assessment.file_deposit_recommended === false;
const conflicts = Array.isArray(assessment.constraint_conflicts) ? assessment.constraint_conflicts : [];
const unresolved = Array.isArray(assessment.unresolved_constraints) ? assessment.unresolved_constraints : [];
const capability = repository.capabilities || assessment.capabilities || {};
if (!metadataOnly && !restricted && !conflicts.length && !unresolved.length && !capability.reviewed) return "";
const heading = metadataOnly ? "Metadata registration only" : restricted ? "Review required before file deposit" : "Repository requirement checks";
return `<section class="policy-notes rb-repository-constraints">
<h5>${esc(rbText(heading))}</h5>
${metadataOnly ? `<p>${esc(rbText("Register metadata with KU Library. Dataset file hosting, DOI assignment, embargo and versioning need separate confirmation."))}</p>` : ""}
${restricted && !metadataOnly ? `<p>${esc(rbText("File deposit is not recommended until the repository and KU Library confirm the requirements for this dataset."))}</p>` : ""}
${assessment.sensitive_data_review_required ? `<p><strong>${esc(rbText("Sensitive-data review required. Do not upload identifiable or confidential files."))}</strong></p>` : ""}
${(conflicts.length || unresolved.length) ? `<ul class="checks-list">${[...conflicts, ...unresolved].map(item => `<li>${esc(item)}</li>`).join("")}</ul>` : ""}
${capability.reviewed ? `<p>${esc(rbText("Capability record reviewed:"))} ${esc(capability.reviewed)}</p>` : ""}
</section>`;
}
function rbRenderPolicyEvaluation(evaluation) {
if (!evaluation) return "";
const label = { meets: "Selected context appears compatible", conditional: "Conditional — review the applicable option", does_not_meet: "Selected context is not permitted by the assessed options", unknown: "Selected-context applicability is unknown" }[evaluation.state] || "Selected-context applicability is unknown";
const unresolved = Array.isArray(evaluation.unresolved_conditions) ? evaluation.unresolved_conditions : [];
const selected = evaluation.selected_option || {};
return `<section class="policy-notes rb-context-evaluation"><p><strong>${esc(rbText(label))}</strong></p>
${selected.where ? `<p><strong>${esc(rbText("Where"))}:</strong> ${esc(selected.where)}</p>` : ""}
${selected.licence ? `<p><strong>${esc(rbText("Licence"))}:</strong> ${esc(selected.licence)}</p>` : ""}
${selected.embargo ? `<p><strong>${esc(rbText("Embargo"))}:</strong> ${esc(selected.embargo)}</p>` : ""}
${unresolved.length ? `<ul class="checks-list">${unresolved.map(item => `<li>${esc(item)}</li>`).join("")}</ul>` : ""}
</section>`;
}
function renderRepoSpecs(repository) {
const specs = [
["Max file size", repository.max_file_size],
["Licences", repository.licences_supported],
["Persistent ID", repository.persistent_identifier],
["Versioning", repository.versioning],
["Embargo support", repository.embargo_support],
["Access model", repository.access_model],
["Sensitive data", repository.sensitive_data_suitable],
["Curation", repository.curation],
].filter(([, value]) => String(value || "").trim());
if (!specs.length) return "";
return `<dl class="r-specs">${specs.map(([label, value]) =>
`<div><dt>${esc(label)}</dt><dd>${esc(value)}</dd></div>`).join("")}</dl>`;
}
function renderRepoCard(r, idx) {
const isKhazna = r.is_khazna;
const verify = r.verify_links || {};
const confidence = r.fit_confidence || r.confidence || "";
const verification = r.verified_note || r.verification_status || "";
return `
<div class="card j-card r-card ${isKhazna ? "is-khazna" : ""}">
<div class="j-header">
<div class="j-meta">#${idx + 1} · ${esc(r.type)} · ${esc(r.cost)}${isKhazna ? " · KU Institutional" : ""}</div>
<div class="j-title">
${rbTrustedAnchor(r.url, r.name)}
${r.url ? `<a href="${esc(safeHttpsUrl(r.url))}" target="_blank" rel="noopener noreferrer" style="font-size:14px;font-family:system-ui,sans-serif;font-weight:400;color:var(--primary);margin-left:8px" class="btn btn-ghost">${esc(rbText("Visit repository"))} ↗</a>` : ""}
</div>
<div class="badge-row">
${confidence ? confidenceBadge(confidence) : ""}
${r.access_model ? accessBadge(r.access_model) : ""}
${r.fair_alignment ? fairBadge(r.fair_alignment) : ""}
${r.certification && r.certification !== "None" ? `<span class="badge b-accent">${esc(r.certification)}</span>` : ""}
</div>
</div>
<div class="j-body">
<p style="color:var(--text-muted);font-size:13px">${esc(r.scope)}</p>
<div class="detail-grid">
<div class="detail-item"><h5>Why it fits</h5><p>${esc(r.fit_reason || "Selected from the curated registry for this dataset profile.")}</p></div>
<div class="detail-item"><h5>Data types</h5><p>${esc(r.data_types_accepted)}</p></div>
</div>
<hr class="divider">
${renderRepoSpecs(r)}
${rbRenderRepositoryConstraints(r)}
${verification ? `<p style="font-size:12px"><strong>Verification:</strong> ${esc(verification)}</p>` : ""}
${!isKhazna ? `
<div class="verify-row">
<span class="verify-lbl">Verify on:</span>
${verify.re3data ? `<a href="${esc(safeHttpsUrl(verify.re3data))}" target="_blank" rel="noopener noreferrer" class="vlink">re3data ↗</a>` : ""}
${verify.fairsharing ? `<a href="${esc(safeHttpsUrl(verify.fairsharing))}" target="_blank" rel="noopener noreferrer" class="vlink">FAIRsharing ↗</a>` : ""}
${r.source_url ? `<a href="${esc(safeHttpsUrl(r.source_url))}" target="_blank" rel="noopener noreferrer" class="vlink">Registry source ↗</a>` : ""}
</div>` : `
<div class="verify-row">
<span class="verify-lbl">Contact:</span>
<a href="mailto:khazna@ku.ac.ae" class="vlink">khazna@ku.ac.ae</a>
<a href="https://khazna.ku.ac.ae" target="_blank" rel="noopener noreferrer" class="vlink">khazna.ku.ac.ae ↗</a>
</div>`}
</div>
</div>`;
}
function renderNextActions(actions, global_notes) {
if (!actions?.length) return "";
return `
<div class="card mt-6">
<div class="card-header"><h2>✅ Next best actions</h2></div>
<div class="card-body">
<ol class="actions-list">
${actions.map((a, i) => `
<li class="action-item">
<span class="a-num">${i + 1}</span>
<span>${esc(a)}</span>
</li>`).join("")}
</ol>
${global_notes ? `<p class="global-note">${esc(global_notes)}</p>` : ""}
</div>
</div>`;
}
function renderManuscriptUnderstanding(m) {
if (!m) return "";
return `
<div class="card understanding">
<div class="card-header"><h2>🧠 Manuscript understanding</h2></div>
<div class="card-body">
<p style="font-size:14px">${esc(m.summary)}</p>
<div class="tag-row">
${m.discipline ? `<span class="badge b-primary">${esc(m.discipline)}</span>` : ""}
${m.article_type ? `<span class="badge b-muted">${esc(m.article_type)}</span>` : ""}
</div>
${m.inferred_criteria?.length ? `
<div>
<h5 style="font-size:13px;font-weight:600;margin-bottom:6px">Inferred selection criteria</h5>
<ul style="list-style:disc;padding-left:18px;display:flex;flex-direction:column;gap:3px">
${m.inferred_criteria.map(c => `<li style="font-size:13px;color:var(--text-muted)">${esc(c)}</li>`).join("")}
</ul>
</div>` : ""}
${m.assumptions?.length ? `
<div class="acc">
<button class="acc-btn" onclick="this.nextElementSibling.classList.toggle('open')">
Assumptions made (${m.assumptions.length}) <span>▾</span>
</button>
<div class="acc-body">
<ul>${m.assumptions.map(a => `<li>${esc(a)}</li>`).join("")}</ul>
</div>
</div>` : ""}
</div>
</div>`;
}
function renderSubmissionChecklist(sc) {
if (!sc) return "";
const steps = (sc.key_steps || []).map((s, i) =>
`<li class="action-item"><span class="a-num">${i+1}</span><span>${esc(s)}</span></li>`
).join("");
const docs = (sc.required_documents || []).map(d =>
`<li style="font-size:13px;color:var(--text-muted)">${esc(d)}</li>`
).join("");
return `
<div class="acc">
<button class="acc-btn" onclick="this.nextElementSibling.classList.toggle('open');this.querySelector('.acc-arrow').classList.toggle('open')">
<span>📋 Submission checklist &amp; requirements</span>
<span class="acc-arrow" style="transition:transform .2s;display:inline-block">▾</span>
</button>
<div class="acc-body">
<dl class="r-specs" style="margin-bottom:12px">
<div><dt>Submission system</dt><dd>${esc(sc.submission_system || "Not specified")}</dd></div>
<div><dt>Word limit</dt><dd>${esc(sc.word_limit || "Not specified")}</dd></div>
<div><dt>Cover letter required</dt><dd>${esc(sc.cover_letter_required || "Unclear")}</dd></div>
<div><dt>Data availability</dt><dd>${esc(sc.data_availability_statement || "Unclear")}</dd></div>
<div><dt>Ethical approval</dt><dd>${esc(sc.ethical_approval || "If applicable")}</dd></div>
</dl>
${sc.formatting_notes ? `<p style="font-size:13px;margin-bottom:10px"><strong>Formatting:</strong> ${esc(sc.formatting_notes)}</p>` : ""}
${docs ? `<div style="margin-bottom:10px"><strong style="font-size:13px">Required documents:</strong><ul style="list-style:disc;padding-left:18px;margin-top:4px">${docs}</ul></div>` : ""}
${steps ? `<div><strong style="font-size:13px">Key submission steps:</strong><ol class="actions-list" style="margin-top:6px">${steps}</ol></div>` : ""}
</div>
</div>`;
}
function renderCoverLetterBtn(journal, manuscript, uid) {
const key = rbDomKey(uid || journal.issn || journal.name, "journal");
RB_COVER_LETTER_PAYLOADS.set(key, {
journalName: String(journal.name || ""),
publisher: String(journal.publisher || ""),
manuscriptTitle: String(manuscript?.title || ""),
abstract: String(manuscript?.abstract || "").substring(0, 5000),
articleType: String(manuscript?.article_type || "Original research article"),
discipline: String(manuscript?.discipline || ""),
});
return `
<p class="rb-cover-letter-notice">Draft only. Verify every claim and complete author confirmations for originality, approval, conflicts of interest and ethics before sending.</p>
<button type="button" class="btn btn-ghost rb-cover-letter-btn"
style="margin-top:4px;font-size:13px" data-cover-id="${key}">
✉ Generate cover letter
</button>
<div id="cover-letter-${key}" aria-live="polite"></div>`;
}
function wireCoverLetterButtons(root) {
root.querySelectorAll(".rb-cover-letter-btn").forEach(btn => {
btn.addEventListener("click", () => {
const payload = RB_COVER_LETTER_PAYLOADS.get(btn.dataset.coverId || "");
if (payload) window.ResearchBee.generateCoverLetter(payload, btn);
});
});
}
// ── Altmetric badge — async loaded after journal cards render ─────────────
function renderAltmetricPlaceholder(issn) {
if (!issn) return "";
const uid = issn.replace(/[^a-zA-Z0-9]/g, "");
return `<div id="altmetric-${uid}"></div>`;
}
async function loadAltmetricBadge(issn) {
if (!issn) return;
const uid = issn.replace(/[^a-zA-Z0-9]/g, "");
const container = document.getElementById(`altmetric-${uid}`);
if (!container) return;
try {
const r = await fetch(`${_HF}/api/altmetric?issn=${encodeURIComponent(issn)}`);
if (!r.ok) return;
const data = await r.json();
if (!data.score) return;
container.innerHTML = `
<div class="altmetric-wrap">
<span class="altmetric-label">Altmetric</span>
${data.image
? `<a href="${data.url || '#'}" target="_blank" rel="noopener">
<img src="${data.image}" class="altmetric-img" alt="Altmetric score ${data.score}">
</a>`
: `<a href="${data.url || '#'}" target="_blank" class="altmetric-score-pill">${data.score}</a>`}
<span class="altmetric-score-label">Score: <strong>${data.score}</strong></span>
<a href="https://www.altmetric.com/about-our-data/our-sources/"
target="_blank" class="altmetric-src">What is this?</a>
</div>`;
} catch (_) { /* silent fail — Altmetric is optional enrichment */ }
}
// ── Related works accordion — lazy loaded on click ────────────────────────
function renderRelatedWorksAccordion(journal, uid) {
const sourceId = String((journal.openalex || {}).openalex_id || "");
const issn = String(journal.issn || "");
if (!sourceId && !issn) return "";
const key = rbDomKey(uid || issn || sourceId, "related");
RB_RELATED_WORK_PAYLOADS.set(key, { sourceId, issn });
return `
<div class="acc rb-related-works" style="margin-top:0" data-related-id="${key}">
<button type="button" class="acc-btn rb-related-toggle"
data-related-id="${key}" aria-expanded="false" aria-controls="rw-${key}">
<span>📄 Related works in this journal</span>
<span class="acc-arrow" style="transition:transform .2s;display:inline-block" aria-hidden="true">▾</span>
</button>
<div class="acc-body" id="rw-${key}">
<div class="rw-tabs" style="display:flex;gap:0;border-bottom:1px solid var(--border);margin-bottom:10px" role="tablist">
<button type="button" class="rw-tab active rb-rw-tab" id="rwtab-cited-${key}"
data-related-id="${key}" data-rw-tab="cited" role="tab" aria-selected="true"
style="padding:6px 14px;font-size:12px;font-weight:600;border:none;background:none;cursor:pointer;border-bottom:2px solid #4338CA;color:#4338CA;font-family:system-ui,sans-serif">
Highly cited
</button>
<button type="button" class="rw-tab rb-rw-tab" id="rwtab-chain-${key}"
data-related-id="${key}" data-rw-tab="chain" role="tab" aria-selected="false"
style="padding:6px 14px;font-size:12px;font-weight:600;border:none;background:none;cursor:pointer;border-bottom:2px solid transparent;color:var(--text-muted);font-family:system-ui,sans-serif">
Citation chain
</button>
</div>
<div id="rwpanel-cited-${key}" role="tabpanel"><div class="rw-loading">Open this section to load works.</div></div>
<div id="rwpanel-chain-${key}" role="tabpanel" style="display:none">
<p style="font-size:12px;color:var(--text-muted);padding:4px 0 8px">
Select a paper from “Highly cited”, then choose <strong>See who cites this →</strong>
</p>
</div>
</div>
</div>`;
}
function wireRelatedWorks(root) {
root.querySelectorAll(".rb-related-toggle").forEach(btn => {
btn.addEventListener("click", () => {
const uid = btn.dataset.relatedId || "";
const body = document.getElementById(`rw-${uid}`);
if (!body) return;
const open = !body.classList.contains("open");
body.classList.toggle("open", open);
btn.setAttribute("aria-expanded", String(open));
btn.querySelector(".acc-arrow")?.classList.toggle("open", open);
if (open) window.ResearchBee._loadRelatedWorks(uid);
});
});
root.querySelectorAll(".rb-rw-tab").forEach(btn => {
btn.addEventListener("click", () => {
window.ResearchBee._switchRwTab(btn.dataset.relatedId || "", btn.dataset.rwTab || "cited");
});
});
}
window.ResearchBee._switchRwTab = function(uid, tab) {
["cited", "chain"].forEach(name => {
const btn = document.getElementById(`rwtab-${name}-${uid}`);
const panel = document.getElementById(`rwpanel-${name}-${uid}`);
if (!btn || !panel) return;
const active = name === tab;
btn.classList.toggle("active", active);
btn.style.borderBottomColor = active ? "#4338CA" : "transparent";
btn.style.color = active ? "#4338CA" : "var(--text-muted)";
btn.setAttribute("aria-selected", String(active));
panel.style.display = active ? "block" : "none";
});
};
function appendWorkMeta(meta, work) {
if (work.year) {
const year = document.createElement("span");
year.textContent = String(work.year);
meta.appendChild(year);
}
const citedBy = Number(work.cited_by || 0);
if (Number.isFinite(citedBy) && citedBy > 0) {
const citations = document.createElement("span");
citations.textContent = `📊 ${citedBy.toLocaleString()} citations`;
meta.appendChild(citations);
}
const doi = makeExternalLink(work.doi, "DOI ↗", ["doi.org"]);
if (doi) meta.appendChild(doi);
const openAlex = makeExternalLink(work.openalex_url, "OpenAlex ↗", ["openalex.org"]);
if (openAlex) meta.appendChild(openAlex);
}
function makeWorkItem(work, citationUid = "") {
const item = document.createElement("div");
item.className = "rw-item";
const title = document.createElement("div");
title.className = "rw-title";
title.textContent = String(work.title || "Untitled");
item.appendChild(title);
const authors = Array.isArray(work.authors) ? work.authors.slice(0, 3).filter(Boolean) : [];
if (authors.length) {
const authorLine = document.createElement("div");
authorLine.className = "rw-authors";
authorLine.textContent = authors.join(", ");
item.appendChild(authorLine);
}
const meta = document.createElement("div");
meta.className = "rw-meta";
appendWorkMeta(meta, work);
const workId = safeHttpsUrl(work.openalex_url, ["openalex.org"]);
if (citationUid && workId) {
const chainBtn = document.createElement("button");
chainBtn.type = "button";
chainBtn.textContent = "See who cites this →";
chainBtn.style.cssText = "font-size:11px;background:#e0e7ff;color:#4338CA;border:none;border-radius:4px;padding:2px 7px;cursor:pointer;font-family:system-ui,sans-serif";
chainBtn.addEventListener("click", () => {
window.ResearchBee._startCitationChain(citationUid, workId, String(work.title || "Untitled"));
});
meta.appendChild(chainBtn);
}
item.appendChild(meta);
return item;
}
function renderWorkList(panel, works, citationUid = "", sourceLabel = "Source: OpenAlex") {
const list = document.createElement("div");
list.className = "rw-list";
works.forEach(work => list.appendChild(makeWorkItem(work, citationUid)));
const source = document.createElement("div");
source.className = "rw-src";
source.append(document.createTextNode(`${sourceLabel} · `));
const sourceLink = makeExternalLink("https://openalex.org", "OpenAlex", ["openalex.org"]);
if (sourceLink) source.appendChild(sourceLink);
list.appendChild(source);
panel.replaceChildren(list);
}
window.ResearchBee._loadRelatedWorks = async function(uid) {
// Update only the cited-results panel. The accordion tabs and citation-chain
// panel must remain in the DOM for the chain workflow to function.
const panel = document.getElementById(`rwpanel-cited-${uid}`);
if (!panel || panel.dataset.loaded === "1") return;
panel.dataset.loaded = "1";
setInlineMessage(panel, "Loading related works...");
const source = RB_RELATED_WORK_PAYLOADS.get(uid) || {};
const cleanId = rbOpenAlexId(source.sourceId);
if (!cleanId) {
setInlineMessage(panel, "No OpenAlex source ID is available for this journal.");
return;
}
try {
const data = await rbFetchJson(`${_HF}/api/openalex-works?source_id=${encodeURIComponent(cleanId)}&per_page=5`, {}, { timeoutMs: 20000 });
const works = Array.isArray(data.works) ? data.works : [];
if (!works.length) {
setInlineMessage(panel, "No works data are available for this journal.");
return;
}
renderWorkList(panel, works, uid, "Highly cited works");
} catch (_) {
panel.dataset.loaded = "";
setInlineMessage(panel, "Could not load works data.", "error");
}
};
// ── Deeper Analysis Strip — links to Scopus, WoS, SciVal ─────────────────
const KU_PROXY = "http://login.khalifa.idm.oclc.org/login?url=";
const SCOPUS_URL = `${KU_PROXY}https://www.scopus.com`;
const WOS_URL = `${KU_PROXY}https://www.webofscience.com`;
const SCIVAL_URL = `${KU_PROXY}https://www.scival.com`;
function renderDeeperAnalysisStrip(journalName, issn) {
const q = issn
? `${KU_PROXY}https://www.scopus.com/sources?ORIGIN=SRCTITLE&title=${encodeURIComponent(journalName)}`
: `${KU_PROXY}https://www.scopus.com/sources`;
return `
<div class="deeper-analysis-strip">
<span class="deeper-analysis-label">🔬 Deeper analysis:</span>
<a href="${esc(q)}" target="_blank" rel="noopener" class="da-link da-scopus">📊 Scopus Sources</a>
<a href="${esc(WOS_URL)}" target="_blank" rel="noopener" class="da-link da-wos">🔬 Web of Science</a>
<a href="${esc(SCIVAL_URL)}" target="_blank" rel="noopener" class="da-link da-scival">📈 SciVal</a>
</div>`;
}
function renderSubjectDeeperAnalysisStrip() {
return `
<div class="subject-deeper-strip">
<span style="font-size:13px;font-weight:600;color:var(--text-muted)">🔬 For citation analysis, author metrics &amp; research performance:</span>
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:8px">
<a href="${esc(SCOPUS_URL)}" target="_blank" rel="noopener" class="da-link da-scopus">📊 Scopus</a>
<a href="${esc(WOS_URL)}" target="_blank" rel="noopener" class="da-link da-wos">🔬 Web of Science</a>
<a href="${esc(SCIVAL_URL)}" target="_blank" rel="noopener" class="da-link da-scival">📈 SciVal</a>
<a href="https://library.ku.ac.ae/lib" target="_blank" rel="noopener" class="da-link da-library">🏛️ KU Library</a>
</div>
</div>`;
}
// ── Trending papers placeholder — loaded async via window.ResearchBee._loadTrendingPapers ─
function renderTrendingPapersSection(concept, conceptId) {
if (!concept && !conceptId) return "";
const uid = (concept || "").replace(/[^a-zA-Z0-9]/g, "").slice(0, 20) || "topic";
const _HF = "https://nikeshn-researchbee.hf.space";
return `
<div class="trending-papers-wrap">
<button class="ext-toggle" onclick="
this.classList.toggle('open');
var b = this.nextElementSibling;
b.style.display = b.style.display === 'none' || b.style.display === '' ? 'block' : 'none';
window.ResearchBee._loadTrendingPapers('${uid}', '${encodeURIComponent(conceptId || concept || "")}', '${esc(concept || "")}');
">
<span>📈 Trending papers in ${esc(concept || "this field")}</span>
<span class="ext-arrow">▼</span>
</button>
<div id="trending-${uid}" style="display:none;margin-top:6px">
<div style="font-size:12px;color:var(--text-muted);padding:8px">Click to load trending papers...</div>
</div>
</div>`;
}
// Global — called from inline onclick
window.ResearchBee._loadTrendingPapers = async function(uid, conceptParam, conceptLabel) {
const container = document.getElementById(`trending-${uid}`);
if (!container || container.dataset.loaded) return;
container.dataset.loaded = "1";
container.innerHTML = `<div style="font-size:12px;color:var(--text-muted);padding:8px">Loading trending papers...</div>`;
try {
const _HF = "https://nikeshn-researchbee.hf.space";
const concept = decodeURIComponent(conceptParam);
// Route through HF backend to avoid CORS issues with direct OpenAlex calls
const isConceptId = /^C\d+$/.test(concept);
const params = isConceptId
? `concept_id=${encodeURIComponent(concept)}&per_page=5`
: `concept=${encodeURIComponent(concept)}&per_page=5`;
const r = await fetch(`${_HF}/api/trending-papers?${params}`);
if (!r.ok) throw new Error("API error");
const data = await r.json();
const works = data.works || [];
if (!works.length) {
container.innerHTML = `<p style="font-size:13px;color:var(--text-muted);padding:8px">No trending papers found for this field.</p>`;
return;
}
const rows = works.map(w => {
const authors = (w.authors || []).join(", ");
const journal = w.journal || "";
const doi = w.doi ? `<a href="${w.doi}" target="_blank" class="vlink" style="font-size:11px">DOI ↗</a>` : "";
const oaLink = w.openalex_url ? `<a href="${w.openalex_url}" target="_blank" class="vlink" style="font-size:11px">OpenAlex ↗</a>` : "";
return `
<div class="rw-item">
<div class="rw-title">${w.title || "Untitled"}</div>
${authors ? `<div class="rw-authors">${authors}${journal ? ` · <em>${journal}</em>` : ""}</div>` : ""}
<div class="rw-meta">
${w.year ? `<span>${w.year}</span>` : ""}
${w.cited_by ? `<span>📊 ${w.cited_by.toLocaleString()} citations</span>` : ""}
${doi} ${oaLink}
</div>
</div>`;
}).join("");
container.innerHTML = `
<div class="rw-list">
${rows}
<div class="rw-src">Source: <a href="https://openalex.org" target="_blank" rel="noopener noreferrer" class="vlink">OpenAlex</a> · Most cited · Last 3 years</div>
</div>`;
} catch(e) {
container.innerHTML = `<p style="font-size:13px;color:var(--text-muted);padding:8px">Could not load trending papers.</p>`;
}
};
// ── Citation chaining — forward citations for a selected paper ────────────
window.ResearchBee._startCitationChain = async function(uid, workId, title) {
window.ResearchBee._switchRwTab(uid, "chain");
const chainPanel = document.getElementById(`rwpanel-chain-${uid}`);
if (!chainPanel) return;
const heading = document.createElement("p");
heading.style.cssText = "font-size:12px;color:var(--text-muted);margin-bottom:8px";
heading.append(document.createTextNode("Papers citing: "));
const strong = document.createElement("strong");
strong.textContent = String(title || "Untitled");
heading.appendChild(strong);
const loading = document.createElement("div");
loading.className = "rw-loading";
loading.textContent = "Loading citing papers...";
chainPanel.replaceChildren(heading, loading);
const cleanId = rbOpenAlexId(workId, "W");
if (!/^W\d+$/.test(cleanId)) {
setInlineMessage(chainPanel, "Invalid OpenAlex work identifier.", "error");
return;
}
try {
const data = await rbFetchJson(`${_HF}/api/openalex-cited-by?work_id=${encodeURIComponent(cleanId)}&per_page=5`, {}, { timeoutMs: 20000, requestKey: `citation:${uid}` });
const works = Array.isArray(data.works) ? data.works : [];
if (!works.length) {
setInlineMessage(chainPanel, "No citing papers were found for this work.");
return;
}
const results = document.createElement("div");
renderWorkList(results, works, "", "Forward citations");
const back = document.createElement("button");
back.type = "button";
back.textContent = "← Back to highly cited";
back.style.cssText = "font-size:11px;margin-top:6px;background:none;border:1px solid var(--border);border-radius:6px;padding:3px 10px;cursor:pointer;color:var(--text-muted);font-family:system-ui,sans-serif";
back.addEventListener("click", () => window.ResearchBee._switchRwTab(uid, "cited"));
chainPanel.replaceChildren(heading, results, back);
} catch (_) {
setInlineMessage(chainPanel, "Could not load citing papers.", "error");
}
};
// ── KU Journal Finder Guide card ─────────────────────────────────────────
function renderJournalFinderCard() {
return `
<div class="jf-guide-card">
<div class="jf-guide-left">
<div class="jf-guide-icon">📖</div>
<div>
<h4 class="jf-guide-title">KU Library Journal Finder Guide</h4>
<p class="jf-guide-desc">
Explore 20+ journal finder tools — publisher-specific finders (Elsevier, Springer, Wiley, IEEE &amp; more),
AI matchers, indexing checkers, and OA verifiers — all curated by KU Library.
</p>
</div>
</div>
<a href="https://library.ku.ac.ae/journalfinder"
target="_blank" rel="noopener"
class="jf-guide-btn">
Open Guide ↗
</a>
</div>`;
}
/* ------------------------------------------------------------------ */
RB_ROOT.querySelectorAll('img[data-rb-mascot]').forEach((img) => { img.src = MASCOT; });
// render_license.js — rendering helpers for the verified-sources License tab.
//
// Design rule mirrored from the backend: the UI must never make an answer look
// more certain than it is. Provenance is always visible, and "we could not
// check" is rendered differently from "it is not there".
// ── Provenance badge ──────────────────────────────────────────────────────
function provenanceBadge(green, sourceMode) {
const status = green?.policy_status || "Not confirmed";
const apiSourced = green?.source_type === "open_policy_finder_api" &&
(status === "Confirmed" || sourceMode === "journal_api");
if (apiSourced) {
return `<span class="prov-badge prov-api" title="Retrieved from the authenticated Jisc Open Policy Finder API; journal-level scope">
✓ Verified source &middot; Open Policy Finder API &middot; journal-level
</span>`;
}
if (status === "Confirmed") {
return `<span class="prov-badge prov-verified" title="Retrieved from an article-level permission database">
✓ Verified &middot; OA.Works Permissions &middot; article-level
</span>`;
}
const label = sourceMode === "doi"
? "No record found for this article"
: "Policy not retrieved";
return `<span class="prov-badge prov-unverified" title="No policy record could be retrieved">
⚠ ${label}
</span>`;
}
// ── Source panel: where every fact came from ──────────────────────────────
function renderSourcePanel(green, result) {
const apiSourced = green?.source_type === "open_policy_finder_api" && green?.policy_status === "Confirmed";
const articleVerified = green?.policy_status === "Confirmed" && !apiSourced;
const urls = Array.isArray(green?.evidence_urls) ? green.evidence_urls.map(url => safeHttpsUrl(url)).filter(Boolean) : [];
const verifyUrl = safeHttpsUrl(green?._verify_url) || "https://openpolicyfinder.jisc.ac.uk/";
const panelClass = apiSourced ? "sp-api" : articleVerified ? "sp-verified" : "sp-unverified";
const icon = apiSourced ? "📚" : articleVerified ? "🔒" : "⚠️";
const heading = apiSourced
? "Source: Jisc Open Policy Finder API"
: articleVerified
? "Where this article-level answer came from"
: "Policy details were not retrieved";
const linkLabel = apiSourced
? "Check current policy on Open Policy Finder"
: "Check Open Policy Finder";
const evidenceLinks = urls.filter(u => u && u !== verifyUrl).slice(0, 4);
return `
<div class="source-panel ${panelClass}">
<div class="sp-head">
<span class="sp-icon">${icon}</span>
<strong>${heading}</strong>
</div>
<p class="sp-note">${esc(green?.evidence_note || "")}</p>
${green?.policy_updated ? `
<p class="sp-meta">Policy record last updated: <strong>${esc(green.policy_updated)}</strong>
${green.monitoring ? ` &middot; monitoring: ${esc(green.monitoring)}` : ""}</p>` : ""}
${green?.policy_issuer ? `
<p class="sp-meta">Policy set by: <strong>${esc(green.policy_issuer)}</strong>
${green.journal_oa_type ? ` &middot; journal type: ${esc(green.journal_oa_type)}` : ""}</p>` : ""}
${apiSourced ? `<p class="sp-meta">Source data: Jisc Open Policy Finder. Licensed CC BY-NC-ND 4.0. Journal-level policy options may require an applicability check.</p>` : ""}
<div class="sp-links">
${evidenceLinks.map((u, i) =>
`<a href="${esc(safeHttpsUrl(u))}" target="_blank" rel="noopener noreferrer" class="sp-link">Policy evidence ${i + 1}</a>`).join("")}
<a href="${esc(verifyUrl)}" target="_blank" rel="noopener noreferrer" class="sp-link sp-link-primary">
${linkLabel}
</a>
${result?.doi_url ? `<a href="${esc(safeHttpsUrl(result.doi_url))}" target="_blank" rel="noopener noreferrer" class="sp-link">View article</a>` : ""}
</div>
</div>`;
}
// ── Deposit statement — must be reproduced verbatim ───────────────────────
function renderDepositStatement(green) {
const stmt = green?.deposit_statement;
if (!stmt) return "";
return `
<div class="deposit-stmt">
<div class="ds-head">
<span>📋 Required deposit statement</span>
<button type="button" class="ds-copy" data-stmt="${esc(stmt)}">Copy</button>
</div>
<p class="ds-body">${esc(stmt)}</p>
<p class="ds-note">The publisher requires this exact wording to accompany your deposited file.
Reproduce it verbatim &mdash; do not paraphrase.</p>
</div>`;
}
// ── Khazna deposit status — three-valued ──────────────────────────────────
function renderKhaznaStatus(k) {
if (!k) return "";
if (!k.checked) {
return `
<div class="khazna-status ks-unknown">
<span class="ks-icon">❔</span>
<div>
<strong>KU repository status not checked</strong>
<p>${esc(k.reason === "no DOI supplied"
? "Enter your article's DOI to check whether it is already in the KU repository, Khazna."
: "The KU repository index is temporarily unavailable, so we could not check. This does not mean the article is absent from Khazna.")}</p>
</div>
</div>`;
}
if (!k.in_khazna) {
return `
<div class="khazna-status ks-absent">
<span class="ks-icon">📭</span>
<div>
<strong>${esc(rbText("Not found in loaded snapshot"))}</strong>
<p>${esc(rbText(k.message || "This DOI was not found in the loaded Khazna snapshot. Confirm in the live portal before creating another record."))}</p>
${k.freshness_note ? `<p class="ks-meta">${esc(k.freshness_note)}</p>` : ""}
</div>
</div>`;
}
const state = k.deposit_state || "undetermined";
const cls = { open: "ks-open", embargoed: "ks-embargo", restricted: "ks-restricted",
closed: "ks-restricted", metadata_only: "ks-gap" }[state] || "ks-unknown";
const icon = { open: "✅", embargoed: "⏳", restricted: "🔒",
closed: "🔒", metadata_only: "📄" }[state] || "❔";
return `
<div class="khazna-status ${cls}">
<span class="ks-icon">${icon}</span>
<div>
<strong>${esc(rbText("Found in loaded snapshot"))} &mdash; ${esc(state.replace("_", " "))}</strong>
<p>${esc(k.message)}</p>
${k.freshness_note ? `<p class="ks-meta">${esc(k.freshness_note)}</p>` : ""}
${k.embargo_end ? `<p class="ks-meta">Embargo ends: <strong>${esc(k.embargo_end)}</strong></p>` : ""}
${k.portal_url ? `<a href="${esc(safeHttpsUrl(k.portal_url))}" target="_blank" rel="noopener" class="ks-link">View the Khazna record →</a>` : ""}
</div>
</div>`;
}
// ── ShareYourPaper deposit call-to-action ─────────────────────────────────
function renderShareYourPaper(result, green) {
if (!result?.shareyourpaper_url || !green?._can_archive) return "";
return `
<div class="syp-card">
<div class="syp-body">
<h4>Deposit this article in minutes</h4>
<p>ShareYourPaper walks you through a legal deposit and checks the file you
upload. It's run by OA.Works, the non-profit whose permissions data powers
this answer.</p>
<a href="${esc(safeHttpsUrl(result.shareyourpaper_url))}" target="_blank" rel="noopener" class="syp-btn">
Open ShareYourPaper →
</a>
</div>
</div>`;
}
// ── Subject repositories — for the ARTICLE, not for data ─────────────────
// Rendered only when OA.Works confirmed a subject repository is permitted.
function renderSubjectRepositories(repos) {
if (!repos?.length) return "";
return `
<div class="card mt-6">
<div class="card-header">
<h2>📚 Subject repositories you may also use</h2>
<p>Your publisher permits deposit in a non-commercial subject repository.
These match this journal's subject area.</p>
</div>
<div class="card-body">
<div class="subj-grid">
${repos.map(r => `
<div class="subj-card">
<div class="subj-head">
<a href="${esc(safeHttpsUrl(r.url))}" target="_blank" rel="noopener">${esc(r.name)}</a>
</div>
<p class="subj-scope">${esc(r.scope)}</p>${rbTrustedAnchor(r.url, rbText("Visit repository"), "btn btn-ghost")}
<dl class="subj-meta">
<div><dt>Versions</dt><dd>${esc(r.versions)}</dd></div>
<div><dt>Review</dt><dd>${esc(r.moderation)}</dd></div>
</dl>
<p class="subj-verified">${esc(r.verified_note || "")}</p>
</div>`).join("")}
</div>
<p class="subj-note">A subject repository does not replace the KU repository,
Khazna &mdash; deposit in both so the work counts towards KU's research portfolio.</p>
</div>
</div>`;
}
// ── Copy-button wiring (call once after rendering) ────────────────────────
function wireCopyButtons(root) {
root.querySelectorAll(".ds-copy").forEach(btn => {
btn.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(btn.dataset.stmt || "");
const original = btn.textContent;
btn.textContent = "Copied ✓";
setTimeout(() => { btn.textContent = original; }, 1800);
} catch {
btn.textContent = "Press Ctrl+C";
}
});
});
}
/* ------------------------------------------------------------------ */
// journal.js - Journal submission tab
const RB_JOURNAL_BASE = "https://nikeshn-researchbee.hf.space";
const KU_OA_LINK = "https://library.ku.ac.ae/oa";
const KU_RATINGS = "https://library.ku.ac.ae/oa/ratings";
// Maps keyword → KU OA publisher page
// Checks if publisher string STARTS WITH or CONTAINS the keyword
function getKuPubPage(publisher) {
const p = (publisher || "")
.toLowerCase()
.replace(/&amp;/g, "&")
.replace(/\.$/g, "")
.trim();
if (p.includes("elsevier")) return "https://library.ku.ac.ae/oa/elsevier";
if (p.startsWith("ieee") || p.includes("ieee ")) return "https://library.ku.ac.ae/oa/ieee";
if (p.includes("american chemical society")) return "https://library.ku.ac.ae/oa/acs";
if (p.includes("springer") || p.includes("nature portfolio")) return "https://library.ku.ac.ae/oa/SpringerNature";
if (p.includes("taylor") || p.includes("routledge")) return "https://library.ku.ac.ae/oa/TandF";
if (p.includes("wiley")) return "https://library.ku.ac.ae/oa/wiley";
return KU_OA_LINK;
}
function journalTab() {
const form = document.getElementById("journal-form");
const results = document.getElementById("journal-results");
const resetBtn= document.getElementById("journal-reset");
if (!form) return;
form.addEventListener("submit", async (e) => {
e.preventDefault();
const submitBtn = form.querySelector(".btn-primary");
submitBtn.disabled = true;
submitBtn.innerHTML = `<span class="btn-spinner"></span> Analysing...`;
results.innerHTML = "";
results.classList.remove("hidden");
showProgress("journal-progress", [
"Analysing your manuscript...",
"Matching journals to your criteria...",
"Enriching with journal metrics...",
"Building results..."
]);
try {
const manuscript = getManuscriptData();
window.ResearchBee.lastManuscript = manuscript;
setStep("journal-progress", 1);
const data = await callAPI("/api/analyze-journal", { manuscript, model: getModel(), language: getLanguage() }, { requestKey: "discovery" });
setStep("journal-progress", 2);
await new Promise(r => setTimeout(r, 300));
setStep("journal-progress", 3);
const result = data.result;
const total = (result.journals?.length || 0) + (result.extended_list?.length || 0);
doneProgress("journal-progress", `[OK] ${total} journals found - ${result.journals?.length || 0} detailed · ${result.extended_list?.length || 0} quick matches`);
setTimeout(() => renderJournalResults(result, results), 400);
} catch (err) {
document.getElementById("journal-progress").innerHTML =
`<div class="p-step" style="color:var(--danger)"><span class="p-dot" style="background:var(--danger)"></span><span>Error: ${esc(err.message)}</span></div>`;
} finally {
submitBtn.disabled = false;
submitBtn.innerHTML = `<span>🔍</span> Find best-fit journals`;
}
});
resetBtn?.addEventListener("click", () => {
results.innerHTML = "";
results.classList.add("hidden");
document.getElementById("journal-progress")?.classList.remove("show");
form.reset();
RB_ROOT.scrollIntoView({ behavior: "smooth", block: "start" });
});
}
function getManuscriptData() {
const g = (id) => document.getElementById(id)?.value?.trim() || "";
return {
title: g("j-title"),
abstract: g("j-abstract"),
keywords: g("j-keywords"),
discipline: g("j-discipline"),
article_type: g("j-article-type"),
methods: g("j-methods"),
audience: g("j-audience"),
funder: g("j-funder"),
institution: g("j-institution"),
country: g("j-country"),
apc_budget: g("j-apc"),
oa_preference: g("j-oa-pref"),
ranking_preference: g("j-ranking-pref"),
ranking_source: g("j-ranking-src"),
speed_preference: g("j-speed"),
preferred_journals: g("j-preferred"),
avoid_journals: g("j-avoid"),
repository_target: g("j-repo-target"),
};
}
function renderJournalFinderPolicySection(oa, policyNotes) {
if (oa?.policy_status === "Confirmed") {
return `
<hr class="divider">
<div>
<h5 style="font-size:14px;font-weight:600;margin-bottom:10px">🟢 Verified Green OA / self-archiving by version</h5>
<div class="version-list">
${renderVersionBlock("Submitted version / preprint", oa.preprint)}
${renderVersionBlock("Accepted manuscript (AAM / postprint)", oa.postprint)}
${renderVersionBlock("Published version (Version of Record)", oa.published_version)}
</div>
</div>
${policyNotes ? `<div class="policy-notes">${policyNotes}</div>` : ""}`;
}
return `
<hr class="divider">
<div class="policy-notes" role="note">
<p><strong>Self-archiving rights are not checked in Journal Finder.</strong></p>
<p>Use <strong>License Checking</strong> with the article DOI before depositing a preprint, accepted manuscript, or Version of Record.</p>
${policyNotes ? policyNotes : ""}
</div>`;
}
function renderJournalCard(j, idx) {
const oa = j.green_oa || {};
const policyNotes = [
oa.licence_notes ? `<p><strong>Licence notes:</strong> ${esc(oa.licence_notes)}</p>` : "",
oa.repository_action_note? `<p><strong>Repository action:</strong> ${esc(oa.repository_action_note)}</p>` : "",
oa.evidence_note ? `<p style="font-style:italic;font-size:12px;color:var(--text-muted)">Evidence: ${esc(oa.evidence_note)}</p>` : "",
oa.risk_flag ? `<p class="p-risk">[!] <span><strong>Risk:</strong> ${esc(oa.risk_flag)}</span></p>` : "",
].filter(Boolean).join("");
// Unique ID for async loaders
const uid = `${rbDomKey(j.issn || j.name, "journal")}-${idx}`;
const _q = (j.ranking || {}).quartile || "";
const _h = parseInt((j.ranking || {}).h_index || (j.openalex || {}).h_index || 0) || 0;
const _qrank = {"Q1":1,"Q2":2,"Q3":3,"Q4":4}[_q] || 9;
const _scop = idxFields(j);
return `
<div class="card j-card"
data-fit="${idx}"
data-quartile="${_qrank}"
data-hindex="${_h}"
data-warn="${_scop.warn ? 1 : 0}"
data-qraw="${esc(_q)}">
<div class="j-header">
<div class="j-meta">#${idx + 1} · ${esc(j.publisher || "")}${j.issn ? ` · ISSN ${esc(j.issn)}` : ""}</div>
<div class="j-title">${rbJournalTitle(j)}</div>${rbJournalLinks(j)}
<div class="badge-row">
${confidenceBadge(j.confidence)}
${j.ranking?.quartile ? quartileBadge(j.ranking.quartile) : ""}
${oaStatusBadge(oa.policy_status || "Not confirmed")}
${diamondBadge(j)}
</div>
</div>
<div class="j-body">
${renderIndexationNotice(j)}
${j.ku_apc_covered ? `
<div class="ku-apc-note">
<div style="display:flex;align-items:flex-start;gap:8px">
<span style="font-size:18px;flex-shrink:0">🎓</span>
<div>
<strong>KU Library may cover the APC for this journal.</strong>
<div style="margin-top:4px;font-size:12px;color:#92400e;line-height:1.5">
This journal is <strong>Q1</strong>${_scop.byField.length > 1 ? " in at least one of its subject areas" : ""} and the publisher has a KU OA agreement.
Verify it is in the <strong>top 15% by Scopus</strong> before submitting your OA request.
</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:8px">
<a href="${getKuPubPage(j.publisher)}" target="_blank" rel="noopener"
style="font-size:12px;font-weight:600;color:#854d0e;text-decoration:underline">
View ${esc(j.publisher || "publisher")} OA process ↗
</a>
<span style="color:#d97706">·</span>
<a href="${KU_RATINGS}" target="_blank" rel="noopener"
style="font-size:12px;font-weight:600;color:#854d0e;text-decoration:underline">
Check top 15% ratings ↗
</a>
</div>
</div>
</div>
</div>` : ""}
<div class="detail-grid">
<div class="detail-item"><h5>🎯 Why it fits</h5><p>${esc(j.fit_reason)}</p></div>
<div class="detail-item"><h5>👥 Audience match</h5><p>${esc(j.audience_match)}</p></div>
<div class="detail-item"><h5>📋 Submission strategy</h5><p>${esc(j.submission_strategy)}</p></div>
<div class="detail-item"><h5>🔓 OA / compliance</h5><p>${esc(j.oa_compliance_note)}</p></div>
</div>
${renderRankingBlock(j.ranking, j)}
${renderJournalFinderPolicySection(oa, policyNotes)}
${renderSubmissionChecklist(j.submission_checklist)}
${renderCoverLetterBtn(j, window.ResearchBee.lastManuscript, uid)}
${renderOpenAlexMetrics(j.openalex)}
<!-- Related works accordion — lazy loaded on click -->
${renderRelatedWorksAccordion(j, uid)}
${renderVerifyLinks(j.verify_links)}
${renderDeeperAnalysisStrip(j.name, j.issn)}
<!-- Altmetric badge — async loaded after render -->
${renderAltmetricPlaceholder(j.issn)}
</div>
</div>`;
}
function renderExtendedList(list) {
if (!list?.length) return "";
const rows = list.map((j, i) => {
const vl = j.verify_links || {};
const q = j.quartile;
const xf = idxFields(j);
const flag = indexationFlag(j);
return `
<tr data-warn="${xf.warn ? 1 : 0}">
<td>${i + 6}</td>
<td><strong>${esc(j.name)}</strong>${xf.diamond ? `<span class="ext-diamond" title="Diamond OA — no APC for authors, no subscription for readers.">◆ Diamond</span>` : ""}<br><span style="font-size:12px;color:var(--text-muted)">${esc(j.publisher || "")}</span></td>
<td style="font-family:ui-monospace,monospace;font-size:12px">${esc(j.issn || "-")}</td>
<td>${q ? quartileBadge(q) : (flag ? "" : '<span style="color:var(--text-light);font-size:12px">-</span>')}${flag}</td>
<td style="font-size:12px;color:var(--text-muted)">${esc(j.fit_reason || "")}</td>
<td>
<div class="ext-links">
${vl.scopus ? `<a href="${esc(safeHttpsUrl(vl.scopus))}" target="_blank" class="el el-scopus">Scopus</a>` : ""}
${vl.sherpa_romeo? `<a href="${esc(safeHttpsUrl(vl.sherpa_romeo))}" target="_blank" class="el el-sherpa">Open Policy Finder</a>` : ""}
${j.ku_apc_covered ? `
<a href="${getKuPubPage(j.publisher)}" target="_blank" class="el" style="background:#fef9c3;color:#854d0e;border:1px solid #fde047" title="KU APC may apply — Q1 journal">🎓 KU APC</a>
<a href="${KU_RATINGS}" target="_blank" class="el" style="background:#fff7ed;color:#c2410c;border:1px solid #fed7aa;font-size:10px" title="Check top 15% eligibility">Check rating ↗</a>
` : ""}
</div>
</td>
</tr>`;
}).join("");
return `
<div class="extended-wrap">
<button class="ext-toggle" onclick="this.classList.toggle('open');this.nextElementSibling.classList.toggle('show')">
<span>📋 Show ${list.length} more journal suggestions</span>
<span class="ext-arrow">▼</span>
</button>
<div class="ext-body">
<table class="ext-table">
<thead>
<tr><th>#</th><th>Journal</th><th>ISSN</th><th>Quartile / status</th><th>Why it fits</th><th>Verify</th></tr>
</thead>
<tbody>${rows}</tbody>
</table>
</div>
</div>`;
}
function renderRepoRecommendation(r) {
if (!r) return "";
return `
<div class="card rec-card mt-6">
<div class="card-header"><h2>🛡 Deposit-rights status</h2></div>
<div class="card-body space-y">
<dl class="rec-grid">
${r.permission_status ? `<div class="rec-item"><dt>Permission</dt><dd>${esc(r.permission_status)}</dd></div>` : ""}
${r.embargo_status ? `<div class="rec-item"><dt>Embargo status</dt><dd>${esc(r.embargo_status)}</dd></div>` : ""}
<div class="rec-item"><dt>Best version to deposit</dt><dd>${esc(r.best_version_to_deposit)}</dd></div>
<div class="rec-item"><dt>Best timing</dt><dd>${esc(r.best_timing)}</dd></div>
<div class="rec-item"><dt>Immediate open deposit</dt><dd>${esc(r.immediate_open_deposit_possible)}</dd></div>
<div class="rec-item"><dt>Embargoed deposit needed</dt><dd>${esc(r.embargoed_deposit_needed)}</dd></div>
<div class="rec-item"><dt>Metadata-only first</dt><dd>${esc(r.metadata_only_first)}</dd></div>
</dl>
${r.khazna_note ? `<div class="policy-notes"><p><strong>Khazna note:</strong> ${esc(r.khazna_note)}</p></div>` : ""}
${r.manual_checks_required?.length ? `
<div>
<h5 style="font-size:13px;font-weight:600;margin-bottom:6px">[!] Manual checks required</h5>
<ul class="checks-list">${r.manual_checks_required.map(c => `<li>${esc(c)}</li>`).join("")}</ul>
</div>` : ""}
</div>
</div>`;
}
function renderJournalResults(result, container) {
// Compatibility guard: any v2 response must use the unified renderer even
// if a LibGuides cache or script ordering issue leaves this legacy handler attached.
if (result?.schema_version === "journal_discovery_v2" && typeof rbV18RenderDiscoveryResults === "function") {
return rbV18RenderDiscoveryResults(result, container, "manuscript");
}
const journals = result.journals || [];
const extended = result.extended_list || [];
const total = journals.length + extended.length;
RB_COVER_LETTER_PAYLOADS.clear();
RB_RELATED_WORK_PAYLOADS.clear();
container.innerHTML = `
${renderMascotRow('Here are your best-fit journal recommendations with verified journal metrics. Deposit rights are checked separately with a DOI.')}
<div class="results-header">
<h2 class="results-title">Analysis</h2>
<div class="results-meta">
<span class="count-chip">${total} journals found</span>
<button class="btn btn-ghost" id="journal-reset">↩ Start over</button>
</div>
</div>
${renderManuscriptUnderstanding(result.manuscript_understanding)}
<h3 style="font-family:Georgia,serif;font-size:22px;margin-bottom:10px">🏆 Best-fit journal shortlist</h3>
<div class="sort-bar" id="journal-sort-bar">
<span class="sort-label">Sort by:</span>
<button class="sort-btn active" data-sort="fit" onclick="window.ResearchBee.sortJournalCards('fit',this)">🎯 Best fit</button>
<button class="sort-btn" data-sort="quartile" onclick="window.ResearchBee.sortJournalCards('quartile',this)">📊 Quartile first</button>
<button class="sort-btn" data-sort="hindex" onclick="window.ResearchBee.sortJournalCards('hindex',this)">📈 H-index</button>
</div>
<div id="journal-cards-wrap">
${journals.map((j, i) => renderJournalCard(j, i)).join("")}
</div>
${renderExtendedList(extended)}
${renderRepoRecommendation(result.repository_recommendation)}
${result.khazna ? renderKhaznaCard(result.khazna, "article") : ""}
<!-- Trending papers — based on first journal's top concept -->
${(() => {
const firstJ = (result.journals || [])[0];
const concept = firstJ?.openalex?.top_concept || result.manuscript_understanding?.discipline || "";
const conceptId = firstJ?.openalex?.top_concept_id || "";
return concept ? renderTrendingPapersSection(concept, conceptId) : "";
})()}
${renderNextActions(result.next_actions, result.global_notes)}
${renderHelpCard()}
${renderJournalFinderCard()}
`;
// Wire export buttons
document.getElementById("export-bibtex")?.addEventListener("click", () => exportCitations(result.journals, "bibtex"));
document.getElementById("export-ris")?.addEventListener("click", () => exportCitations(result.journals, "ris"));
// Reset button
document.getElementById("journal-reset")?.addEventListener("click", () => {
container.innerHTML = "";
container.classList.add("hidden");
document.getElementById("journal-progress")?.classList.remove("show");
document.getElementById("journal-form")?.reset();
RB_ROOT.scrollIntoView({ behavior: "smooth", block: "start" });
});
// Safe event wiring after the HTML skeleton is in the DOM.
wireCoverLetterButtons(container);
wireRelatedWorks(container);
// ── Load Altmetric badges async after render ───────────────────────────
journals.forEach(j => {
if (j.issn) loadAltmetricBadge(j.issn);
});
container.scrollIntoView({ behavior: "smooth", block: "start" });
}
// ── Subject browse mode ────────────────────────────────────────────────────
function subjectTab() {
const form = document.getElementById("subject-form");
const results = document.getElementById("subject-results");
if (!form) return;
form.addEventListener("submit", async (e) => {
e.preventDefault();
const input = document.getElementById("s-subject");
const subject = input?.value?.trim();
if (!subject) return;
const submitBtn = form.querySelector(".btn-primary");
submitBtn.disabled = true;
submitBtn.innerHTML = "Searching journals...";
results.innerHTML = "";
results.classList.remove("hidden");
showProgress("subject-progress", [
"Identifying your subject...",
"Searching journal database...",
"Building results..."
]);
try {
setStep("subject-progress", 1);
const data = await callAPI("/api/browse-subject", {
subject, model: getModel(), language: getLanguage()
});
setStep("subject-progress", 2);
doneProgress("subject-progress",
data.result.journals?.length
? `Found ${data.result.journals.length} journals`
: "Search complete"
);
setTimeout(() => renderSubjectResults(data.result, results), 300);
} catch (err) {
document.getElementById("subject-progress").innerHTML =
`<div class="p-step" style="color:var(--danger)">
<span class="p-dot" style="background:var(--danger)"></span>
<span>Error: ${esc(err.message)}</span>
</div>`;
} finally {
submitBtn.disabled = false;
submitBtn.innerHTML = "Search journals";
}
});
document.getElementById("subject-reset")?.addEventListener("click", resetSubject);
}
function resetSubject() {
const results = document.getElementById("subject-results");
if (results) { results.innerHTML = ""; results.classList.add("hidden"); }
document.getElementById("subject-progress")?.classList.remove("show");
document.getElementById("subject-form")?.reset();
}
function renderSubjectQuartileCell(journal) {
return `<div class="subject-q-item">${renderFieldQuartiles(journal.quartiles_by_field || [])}</div>`;
}
function wireSubjectResultActions(container) {
container.querySelector(".rb-subject-retry")?.addEventListener("click", resetSubject);
container.querySelectorAll(".rb-subject-sort").forEach(btn => {
btn.addEventListener("click", () => {
window.ResearchBee.sortSubjectTable(btn.dataset.sort || "hindex", btn);
});
});
container.querySelectorAll(".rb-subject-copy-issn").forEach(btn => {
btn.addEventListener("click", async () => {
const payload = RB_SUBJECT_JOURNAL_PAYLOADS.get(btn.dataset.subjectId || "");
if (!payload?.issn) return;
try {
await navigator.clipboard.writeText(payload.issn);
const original = btn.textContent;
btn.textContent = "Copied!";
setTimeout(() => { btn.textContent = original; }, 1500);
} catch (_) {
btn.textContent = "Copy failed";
}
});
});
container.querySelectorAll(".rb-subject-cover-toggle").forEach(btn => {
btn.addEventListener("click", () => {
window.ResearchBee.showSubjectCoverLetterForm(btn.dataset.subjectId || "", btn);
});
});
container.querySelectorAll(".rb-subject-analyse").forEach(btn => {
btn.addEventListener("click", () => {
const payload = RB_SUBJECT_JOURNAL_PAYLOADS.get(btn.dataset.subjectId || "");
if (payload) window.ResearchBee.analyseFullyFromSubject(payload.name, payload.issn);
});
});
container.querySelectorAll(".rb-subject-cover-submit").forEach(btn => {
btn.addEventListener("click", () => {
window.ResearchBee.submitSubjectCoverLetter(btn.dataset.subjectId || "", btn);
});
});
container.querySelectorAll(".rb-subject-cover-cancel").forEach(btn => {
btn.addEventListener("click", () => {
const uid = btn.dataset.subjectId || "";
const row = document.getElementById(`clform-${uid}`);
if (row) row.style.display = "none";
const toggle = container.querySelector(`.rb-subject-cover-toggle[data-subject-id="${uid}"]`);
if (toggle) toggle.textContent = "Cover letter";
});
});
}
function renderSubjectResults(result, container) {
// Compatibility guard matching manuscript mode.
if (result?.schema_version === "journal_discovery_v2" && typeof rbV18RenderDiscoveryResults === "function") {
return rbV18RenderDiscoveryResults(result, container, "subject");
}
const journals = result.journals || [];
RB_SUBJECT_JOURNAL_PAYLOADS.clear();
if (result.confidence === "not_found" || !journals.length) {
container.innerHTML = `
<div class="subj-notfound">
<div class="subj-notfound-icon">?</div>
<h3>No journals found</h3>
<p>${esc(result.user_message || "Try a different subject term.")}</p>
<button type="button" class="btn btn-ghost rb-subject-retry">Try again</button>
</div>`;
wireSubjectResultActions(container);
return;
}
const banner = result.user_message
? `<div class="subj-banner">
<span class="subj-banner-icon">${result.confidence === "near" ? "Corrected:" : "Note:"}</span>
${esc(result.user_message)}
</div>`
: "";
const rows = journals.map((journal, index) => {
const verify = journal.verify_links || {};
const uid = `${rbDomKey(journal.issn || journal.name, "subject")}-${index}`;
RB_SUBJECT_JOURNAL_PAYLOADS.set(uid, {
name: String(journal.name || ""),
publisher: String(journal.publisher || ""),
issn: String(journal.issn || ""),
});
const quartile = journal.quartile || "";
const quartileRank = {Q1: 1, Q2: 2, Q3: 3, Q4: 4}[quartile] || 9;
const hIndex = Number(journal.h_index || 0) || 0;
const oaRank = journal.open_access === "Yes" ? 0 : 1;
return `
<tr id="row-${uid}" data-quartile="${quartileRank}" data-hindex="${hIndex}"
data-oa="${oaRank}" data-qraw="${esc(quartile)}" ${quartile === "Q1" ? 'class="q1-row"' : ""}>
<td style="color:var(--text-muted);font-size:12px;font-family:ui-monospace,monospace">${index + 1}</td>
<td>
<strong style="font-size:13px">${esc(journal.name)}</strong>
<div style="font-size:11px;color:var(--text-muted);margin-top:2px">${esc(journal.publisher || "")}</div>
</td>
<td style="font-family:ui-monospace,monospace;font-size:12px">${esc(journal.issn || "-")}</td>
<td>${renderSubjectQuartileCell(journal)}</td>
<td style="font-family:ui-monospace,monospace;font-size:12px">${journal.h_index || "-"}</td>
<td>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:6px">
${verify.scimago ? `<a href="${esc(safeHttpsUrl(verify.scimago))}" target="_blank" rel="noopener noreferrer" class="el el-scopus">SCImago</a>` : ""}
${verify.sherpa_romeo ? `<a href="${esc(safeHttpsUrl(verify.sherpa_romeo))}" target="_blank" rel="noopener noreferrer" class="el el-sherpa">Open Policy Finder</a>` : ""}
${verify.doaj ? `<a href="${esc(safeHttpsUrl(verify.doaj))}" target="_blank" rel="noopener noreferrer" class="el" style="background:#fef3c7;color:#92400e">DOAJ</a>` : ""}
${verify.scopus_sources ? `<a href="${esc(safeHttpsUrl(verify.scopus_sources))}" target="_blank" rel="noopener noreferrer" class="el" style="background:#e0e7ff;color:#3730a3">Scopus</a>` : ""}
${journal.issn ? `<button type="button" class="copy-chip copy-chip-sm rb-subject-copy-issn" data-subject-id="${uid}" title="Copy ISSN">${esc(journal.issn)} 📋</button>` : ""}
${journal.ku_apc_covered ? `
<a href="${getKuPubPage(journal.publisher)}" target="_blank" rel="noopener noreferrer" class="el" style="background:#fef9c3;color:#854d0e;border:1px solid #fde047" title="KU APC may apply — verify title-level eligibility and top-15% requirements.">🎓 KU APC candidate</a>
<a href="${KU_RATINGS}" target="_blank" rel="noopener noreferrer" class="el" style="background:#fff7ed;color:#c2410c;border:1px solid #fed7aa;font-size:10px">Check rating ↗</a>
` : ""}
</div>
<div style="display:flex;gap:6px;flex-wrap:wrap">
<button type="button" class="el rb-subject-cover-toggle" data-subject-id="${uid}"
style="background:#e0e7ff;color:#3730a3;cursor:pointer;border:none">Cover letter</button>
<button type="button" class="el rb-subject-analyse" data-subject-id="${uid}"
style="background:#d1fae5;color:#065f46;cursor:pointer;border:none">Analyse fully</button>
</div>
</td>
</tr>
<tr id="clform-${uid}" style="display:none">
<td colspan="6" style="padding:12px 14px;background:#f8f9fc;border-top:none">
<div class="subj-cl-form">
<p style="font-size:13px;font-weight:600;margin-bottom:10px">Generate cover letter for <em>${esc(journal.name)}</em></p>
<div class="form-grid form-2col" style="max-width:700px;gap:10px">
<div class="form-group">
<label style="font-size:12px" for="cl-title-${uid}">Manuscript title <span class="req">*</span></label>
<input id="cl-title-${uid}" type="text" placeholder="Your manuscript title">
</div>
<div class="form-group">
<label style="font-size:12px" for="cl-author-${uid}">Your name (optional)</label>
<input id="cl-author-${uid}" type="text" placeholder="e.g. Dr. Nikesh">
</div>
<div class="form-group form-full">
<label style="font-size:12px" for="cl-abstract-${uid}">Abstract <span class="req">*</span></label>
<textarea id="cl-abstract-${uid}" rows="4" placeholder="Paste your abstract here..."></textarea>
</div>
</div>
<div style="display:flex;gap:8px;margin-top:10px">
<button type="button" class="btn btn-primary rb-subject-cover-submit" data-subject-id="${uid}"
style="max-width:220px;font-size:13px;padding:10px 16px">Generate &amp; download</button>
<button type="button" class="btn btn-ghost rb-subject-cover-cancel" data-subject-id="${uid}"
style="font-size:13px">Cancel</button>
</div>
<div id="cl-status-${uid}" style="margin-top:8px" aria-live="polite"></div>
</div>
</td>
</tr>`;
}).join("");
container.innerHTML = `
${renderMascotRow('Here are the top journals for ' + esc(result.normalised) + '.')}
<div class="results-header">
<h2 class="results-title">Top journals: ${esc(result.normalised)}</h2>
<div class="results-meta">
<span class="count-chip">${journals.length} journals</span>
<button type="button" class="btn btn-ghost" id="subject-reset-btn">Reset</button>
</div>
</div>
${banner}
<div class="sort-bar" id="subj-sort-bar">
<span class="sort-label">Sort by:</span>
<button type="button" class="sort-btn active rb-subject-sort" data-sort="hindex">📈 H-index</button>
<button type="button" class="sort-btn rb-subject-sort" data-sort="quartile">📊 Quartile first</button>
<button type="button" class="sort-btn rb-subject-sort" data-sort="oa">🔓 OA first</button>
</div>
<div class="card" style="overflow:hidden;margin-bottom:20px">
<table class="ext-table" style="width:100%" id="subj-table">
<thead><tr><th>#</th><th>Journal</th><th>ISSN</th><th>Quartile by field</th><th>H-index</th><th>Verify &amp; Actions</th></tr></thead>
<tbody id="subj-tbody">${rows}</tbody>
</table>
</div>
<div class="subj-tip">
<strong>Want deeper manuscript-fit analysis?</strong>
Switch to <em>Analyse manuscript</em> mode above. Use <em>License Checking</em> with the article DOI for verified deposit rights.
</div>
${renderSubjectDeeperAnalysisStrip()}
${renderJournalFinderCard()}
${renderTrendingPapersSection(result.normalised, result.scimago_concept_id || "")}
`;
document.getElementById("subject-reset-btn")?.addEventListener("click", resetSubject);
wireSubjectResultActions(container);
container.scrollIntoView({ behavior: "smooth", block: "start" });
}
// ── Export citations ──────────────────────────────────────────────────────
async function exportCitations(journals, format) {
try {
const data = await callAPI("/api/export-citations", { journals, format });
const blob = new Blob([data.content], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url; a.download = data.filename; a.click();
URL.revokeObjectURL(url);
} catch(err) {
if (rbStaleRequest(err)) return;
alert("Export failed: " + err.message);
}
}
// ── Cover letter generator ────────────────────────────────────────────────
function renderGeneratedCoverLetter(container, result, journalName) {
const card = document.createElement("div");
card.className = "card";
card.style.cssText = "margin-top:10px;border:1.5px solid var(--primary-light)";
const header = document.createElement("div");
header.className = "card-header";
header.style.background = "var(--primary-xlight)";
const heading = document.createElement("h2");
heading.style.fontSize = "16px";
heading.textContent = `✉ Cover letter — ${journalName}`;
const meta = document.createElement("p");
meta.style.fontSize = "12px";
meta.append(document.createTextNode("Subject line: "));
const subject = document.createElement("strong");
subject.textContent = String(result.subject_line || "");
meta.appendChild(subject);
if (result.word_count) meta.append(document.createTextNode(` · ${result.word_count} words`));
header.append(heading, meta);
const body = document.createElement("div");
body.className = "card-body";
const pre = document.createElement("pre");
pre.style.cssText = "white-space:pre-wrap;font-family:system-ui,sans-serif;font-size:13px;line-height:1.7";
pre.textContent = String(result.cover_letter || "");
const actions = document.createElement("div");
actions.style.cssText = "margin-top:12px;display:flex;gap:8px";
const download = document.createElement("button");
download.type = "button";
download.className = "btn btn-ghost";
download.style.fontSize = "12px";
download.textContent = "⬇ Download .txt";
download.addEventListener("click", () => {
window.ResearchBee.downloadCoverLetter(pre.textContent || "", journalName);
});
const copy = document.createElement("button");
copy.type = "button";
copy.className = "btn btn-ghost";
copy.style.fontSize = "12px";
copy.textContent = "📋 Copy";
copy.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(pre.textContent || "");
copy.textContent = "Copied!";
setTimeout(() => { copy.textContent = "📋 Copy"; }, 1600);
} catch (_) {
copy.textContent = "Copy failed";
}
});
actions.append(download, copy);
body.append(pre, actions);
card.append(header, body);
container.replaceChildren(card);
}
window.ResearchBee.generateCoverLetter = async function(payload, btn) {
const coverId = btn?.dataset?.coverId || "";
const container = document.getElementById(`cover-letter-${coverId}`);
if (!container || !payload) return;
btn.disabled = true;
btn.textContent = "Generating...";
setInlineMessage(container, "Writing cover letter...");
try {
const data = await callAPI("/api/cover-letter", {
manuscript_title: payload.manuscriptTitle,
abstract: payload.abstract,
journal_name: payload.journalName,
publisher: payload.publisher,
article_type: payload.articleType,
discipline: payload.discipline,
language: getLanguage(),
model: getModel(),
});
renderGeneratedCoverLetter(container, data.result || {}, payload.journalName);
rbApplyUiLanguage(container);
} catch (err) {
setInlineMessage(container, `Error: ${String(err.message || err)}`, "error");
} finally {
btn.disabled = false;
btn.textContent = rbText("✉ Generate cover letter");
}
};
window.ResearchBee.downloadCoverLetter = function(text, journalName) {
const blob = new Blob([String(text || "")], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
const safeName = String(journalName || "journal")
.replace(/[^a-zA-Z0-9 _-]/g, "")
.trim()
.replace(/\s+/g, "-")
.toLowerCase()
.slice(0, 60) || "journal";
link.download = `cover-letter-${safeName}.txt`;
link.click();
URL.revokeObjectURL(url);
};
// ── Subject browse cover letter ───────────────────────────────────────────
window.ResearchBee.showSubjectCoverLetterForm = function(uid, btn) {
const row = document.getElementById(`clform-${uid}`);
if (!row) return;
const isVisible = row.style.display !== "none";
row.style.display = isVisible ? "none" : "table-row";
if (btn) btn.textContent = isVisible ? "Cover letter" : "Hide form";
};
window.ResearchBee.submitSubjectCoverLetter = async function(uid, btn) {
const payload = RB_SUBJECT_JOURNAL_PAYLOADS.get(uid);
if (!payload) return;
const title = document.getElementById(`cl-title-${uid}`)?.value?.trim();
const abstract = document.getElementById(`cl-abstract-${uid}`)?.value?.trim();
const author = document.getElementById(`cl-author-${uid}`)?.value?.trim();
const status = document.getElementById(`cl-status-${uid}`);
if (!title || !abstract) {
setInlineMessage(status, "Please fill in title and abstract.", "error");
return;
}
btn.disabled = true;
btn.textContent = "Generating...";
setInlineMessage(status, "Writing cover letter...");
try {
const data = await callAPI("/api/cover-letter", {
manuscript_title: title,
abstract,
journal_name: payload.name,
publisher: payload.publisher,
author_name: author,
language: getLanguage(),
model: getModel(),
});
const result = data.result || {};
const full = `Subject: ${result.subject_line || ""}\n\n${result.cover_letter || ""}`;
window.ResearchBee.downloadCoverLetter(full, payload.name);
setInlineMessage(status, "Downloaded!", "success");
setTimeout(() => { if (status) status.replaceChildren(); }, 3000);
} catch (err) {
setInlineMessage(status, `Error: ${String(err.message || err)}`, "error");
} finally {
btn.disabled = false;
btn.textContent = "Generate & download";
}
};
// ── Analyse fully from subject browse ────────────────────────────────────
window.ResearchBee.analyseFullyFromSubject = function(jName, jIssn) {
const prefField = document.getElementById("j-preferred");
if (prefField) prefField.value = jName;
switchMode("manuscript");
const form = document.getElementById("journal-form");
if (form) {
let notice = document.getElementById("analyse-notice");
if (!notice) {
notice = document.createElement("div");
notice.id = "analyse-notice";
notice.className = "subj-banner";
notice.style.marginBottom = "16px";
form.parentNode.insertBefore(notice, form);
}
const label = document.createElement("span");
label.className = "subj-banner-icon";
label.textContent = "Pre-filled:";
const name = document.createElement("strong");
name.textContent = String(jName || "");
notice.replaceChildren(label, document.createTextNode(" "), name,
document.createTextNode(" added to preferred journals. Add your manuscript details and submit."));
}
RB_ROOT.querySelector(".tabs-bar")?.scrollIntoView({ behavior: "smooth", block: "start" });
};
// ── Manuscript Analysis — sort journal cards ──────────────────────────────
window.ResearchBee.sortJournalCards = function(mode, btn) {
const wrap = document.getElementById("journal-cards-wrap");
if (!wrap) return;
// Update active button
RB_ROOT.querySelectorAll("#journal-sort-bar .sort-btn").forEach(b => b.classList.remove("active"));
btn.classList.add("active");
const cards = Array.from(wrap.querySelectorAll(".j-card"));
cards.sort((a, b) => {
if (mode === "fit") return +a.dataset.fit - +b.dataset.fit;
if (mode === "quartile") return +a.dataset.quartile - +b.dataset.quartile;
if (mode === "hindex") return +b.dataset.hindex - +a.dataset.hindex;
return 0;
});
// Re-number and re-append
cards.forEach((card, i) => {
const meta = card.querySelector(".j-meta");
if (meta) {
meta.textContent = meta.textContent.replace(/^#\d+/, `#${i + 1}`);
}
wrap.appendChild(card);
});
};
// ── Subject Browse — sort table rows ─────────────────────────────────────
window.ResearchBee.sortSubjectTable = function(mode, btn) {
const tbody = document.getElementById("subj-tbody");
if (!tbody) return;
RB_ROOT.querySelectorAll("#subj-sort-bar .sort-btn").forEach(b => b.classList.remove("active"));
btn.classList.add("active");
const rows = Array.from(tbody.querySelectorAll("tr[data-quartile]"));
rows.sort((a, b) => {
if (mode === "quartile") {
const qDiff = +a.dataset.quartile - +b.dataset.quartile;
if (qDiff !== 0) return qDiff;
return +b.dataset.hindex - +a.dataset.hindex; // secondary: h-index desc
}
if (mode === "hindex") return +b.dataset.hindex - +a.dataset.hindex;
if (mode === "oa") return +a.dataset.oa - +b.dataset.oa;
return 0;
});
// Re-number rank column
rows.forEach((row, i) => {
const rankCell = row.querySelector("td:first-child");
if (rankCell) rankCell.textContent = i + 1;
tbody.appendChild(row);
});
};
/* ------------------------------------------------------------------ */
// license.js - License checking tab
const RB_LICENSE_BASE = "https://nikeshn-researchbee.hf.space";
// ── Journal name auto-lookup — multi-suggestion ──────────────────────────
let _lookupTimer = null;
function initJournalLookup() {
const nameInput = document.getElementById("l-journal");
const issnInput = document.getElementById("l-issn");
const pubInput = document.getElementById("l-publisher");
if (!nameInput) return;
const chipWrap = document.createElement("div");
chipWrap.id = "journal-lookup-wrap";
chipWrap.style.cssText = "margin-top:6px;";
nameInput.parentNode.appendChild(chipWrap);
nameInput.addEventListener("input", () => {
clearTimeout(_lookupTimer);
chipWrap.innerHTML = "";
rbCancelRequest("journal-lookup");
[issnInput, pubInput].forEach(field => { if (field?.dataset.autofilled === "1") { field.value = ""; delete field.dataset.autofilled; } });
const val = nameInput.value.trim();
if (val.length < 4) return;
_lookupTimer = setTimeout(() => runLookup(val, nameInput, issnInput, pubInput, chipWrap), 650);
});
}
async function runLookup(name, nameInput, issnInput, pubInput, chipWrap) {
chipWrap.innerHTML = `<span style="font-size:11px;color:var(--text-muted);font-style:italic">🔍 Searching journal database...</span>`;
try {
const data = await rbFetchJson(`${RB_LICENSE_BASE}/api/lookup-journal-meta?name=${encodeURIComponent(name)}`, {}, { requestKey: "journal-lookup", timeoutMs: 20000 });
if (nameInput.value.trim() !== name) return;
const suggestions = data.suggestions || [];
const llmSuggestions = data.llm_suggestions|| [];
// ── SCImago/OpenAlex suggestions — fill name + ISSN + publisher ───────
if (suggestions.length) {
const items = suggestions.map((s, i) => {
const icon = s.confidence === "high" ? "✓" : "~";
const bg = s.confidence === "high" ? "#f0fdf4" : "#fffbeb";
const bc = s.confidence === "high" ? "#6ee7b7" : "#fcd34d";
const tc = s.confidence === "high" ? "var(--success)" : "#92400e";
return `
<button type="button" class="lookup-suggestion-chip" data-idx="${i}" style="
display:flex;align-items:flex-start;gap:8px;width:100%;
background:${bg};border:1.5px solid ${bc};border-radius:9px;
padding:7px 11px;font-family:system-ui,sans-serif;cursor:pointer;
text-align:left;transition:box-shadow .15s;margin-bottom:4px;
"
onmouseover="this.style.boxShadow='0 2px 8px rgba(0,0,0,.1)'"
onmouseout="this.style.boxShadow='none'">
<span style="color:${tc};font-weight:700;font-size:12px;flex-shrink:0;margin-top:1px">${icon}</span>
<span style="flex:1;min-width:0;">
<span style="font-size:12.5px;font-weight:600;color:#1e293b;display:block;line-height:1.3">
${esc(s.title)}
</span>
<span style="font-size:11px;color:var(--text-muted);display:flex;gap:8px;margin-top:2px;flex-wrap:wrap">
${s.issn ? `<span>ISSN: ${esc(s.issn)}</span>` : ""}
${s.publisher? `<span>${esc(s.publisher)}</span>` : ""}
<span style="opacity:.6">${esc(s.source)}</span>
</span>
</span>
</button>`;
}).join("");
chipWrap.innerHTML = `
<div style="font-size:11px;color:var(--text-muted);margin-bottom:4px;font-weight:500">
📚 Select a journal:
</div>
${items}
<button type="button" onclick="document.getElementById('journal-lookup-wrap').innerHTML=''" style="
background:none;border:none;font-size:11px;color:var(--text-muted);
cursor:pointer;padding:2px 4px;margin-top:2px;
">✕ Dismiss</button>`;
// Wire click handlers
chipWrap.querySelectorAll(".lookup-suggestion-chip").forEach(btn => {
btn.addEventListener("click", () => {
const idx = parseInt(btn.dataset.idx);
const s = suggestions[idx];
// Fill journal name field (Option A — fills all fields)
nameInput.value = s.title;
// Fill ISSN + publisher from verified source
issnInput.value = s.issn || "";
issnInput.dataset.autofilled = "1";
pubInput.value = s.publisher || "";
pubInput.dataset.autofilled = "1";
// Show confirmed chip
chipWrap.innerHTML = `
<div style="
display:inline-flex;align-items:center;gap:6px;
background:var(--success-light);border:1px solid #6ee7b7;
border-radius:8px;padding:4px 10px;font-size:11.5px;
color:var(--success);font-family:system-ui,sans-serif;
">
<span style="font-weight:700">✓</span>
<span>Filled from <strong>${esc(s.source)}</strong></span>
<button type="button" onclick="window.ResearchBee.clearAutofill()" style="
background:none;border:none;cursor:pointer;color:var(--success);
font-size:13px;padding:0 2px;opacity:.7;line-height:1;
" title="Clear">×</button>
</div>`;
});
});
// ── LLM name suggestions — fill name only, re-run lookup for ISSN ────
} else if (llmSuggestions.length) {
const items = llmSuggestions.map((s, i) => `
<button type="button" class="lookup-llm-chip" data-idx="${i}" style="
display:inline-flex;align-items:center;gap:6px;
background:#fef3c7;border:1.5px solid #fcd34d;border-radius:20px;
padding:4px 12px;font-size:12px;color:#92400e;
font-family:system-ui,sans-serif;cursor:pointer;
font-weight:500;transition:background .15s;margin:2px;
"
onmouseover="this.style.background='#fde68a'"
onmouseout="this.style.background='#fef3c7'">
💡 ${esc(s.name)}
</button>`).join("");
chipWrap.innerHTML = `
<div style="font-size:11px;color:var(--text-muted);margin-bottom:5px;font-weight:500">
Did you mean one of these?
</div>
<div style="display:flex;flex-wrap:wrap;gap:4px">${items}</div>
<div style="font-size:10.5px;color:var(--text-light);margin-top:4px">
ℹ️ Selecting will search for ISSN automatically
</div>`;
// Wire LLM chip clicks — fill name only, re-run Layer 1 for ISSN
chipWrap.querySelectorAll(".lookup-llm-chip").forEach(btn => {
btn.addEventListener("click", () => {
const idx = parseInt(btn.dataset.idx);
const s = llmSuggestions[idx];
nameInput.value = s.name;
chipWrap.innerHTML = `<span style="font-size:11px;color:var(--text-muted);font-style:italic">🔍 Looking up ISSN for ${esc(s.name)}...</span>`;
// Re-run Layer 1 with corrected name
runLookup(s.name, nameInput, issnInput, pubInput, chipWrap);
});
});
} else {
chipWrap.innerHTML = "";
}
} catch (e) {
if (!rbStaleRequest(e) && nameInput.value.trim() === name) chipWrap.innerHTML = "";
}
}
// Clear auto-fill
window.ResearchBee.clearAutofill = function() {
const issnInput = document.getElementById("l-issn");
const pubInput = document.getElementById("l-publisher");
const chipWrap = document.getElementById("journal-lookup-wrap");
if (issnInput) { issnInput.value = ""; delete issnInput.dataset.autofilled; }
if (pubInput) { pubInput.value = ""; delete pubInput.dataset.autofilled; }
if (chipWrap) chipWrap.innerHTML = "";
};
// ── License tab ───────────────────────────────────────────────────────────
function licenseTab() {
const form = document.getElementById("license-form");
const results = document.getElementById("license-results");
if (!form) return;
let requestGeneration = 0;
form.addEventListener("reset", () => {
requestGeneration += 1;
rbCancelRequest("license");
clearTimeout(_lookupTimer); _lookupTimer = null;
rbCancelRequest("journal-lookup");
window.ResearchBee.clearAutofill();
rbResetFormUi("license");
});
// Init journal lookup on load
initJournalLookup();
// Clear autofill flags when user manually edits ISSN or publisher
document.getElementById("l-issn")?.addEventListener("input", (e) => {
if (e.isTrusted) delete e.target.dataset.autofilled;
});
document.getElementById("l-publisher")?.addEventListener("input", (e) => {
if (e.isTrusted) delete e.target.dataset.autofilled;
});
form.addEventListener("submit", async (e) => {
e.preventDefault();
const chosenInput = getLicenseData();
const doiVal = chosenInput.doi;
const jrnVal = chosenInput.journal_name;
const issnVal = chosenInput.issn;
if (!doiVal && !jrnVal && !issnVal) {
results.classList.remove("hidden");
const message = RB_ROOT.dataset.rbShareMode === "journal"
? "Enter a journal name or ISSN to continue."
: "Enter an article DOI or URL to continue.";
results.innerHTML = `<div class="card"><div class="card-body"><p role="alert" style="color:var(--danger)">${esc(rbText(message))}</p></div></div>`;
document.getElementById(RB_ROOT.dataset.rbShareMode === "journal" ? "l-journal" : "l-doi")?.focus();
return;
}
const generation = ++requestGeneration;
const submitBtns = form.querySelectorAll(".btn-primary");
submitBtns.forEach(b => { b.disabled = true; b.innerHTML = `🔍 Checking policy...`; });
results.innerHTML = "";
results.classList.remove("hidden");
showProgress("license-progress", [
doiVal ? "Resolving DOI..." : "Resolving the journal record...",
doiVal ? "Checking OA.Works Permissions + Khazna..." : "Querying the Jisc Open Policy Finder API...",
doiVal ? "Building deposit guidance..." : "Preparing the journal-level policy options..."
], { requestKey: "license" });
try {
const license_input = getLicenseData();
setStep("license-progress", 1);
const data = await callAPI("/api/check-license", {
license_input, model: getModel(), language: getLanguage()
}, { requestKey: "license" });
if (generation !== requestGeneration) return;
setStep("license-progress", 2);
doneProgress("license-progress", "[OK] Policy check complete");
renderLicenseResults(data.result, results);
rbApplyUiLanguage(results);
} catch (err) {
if (generation !== requestGeneration || rbStaleRequest(err)) return;
failProgress("license-progress", err);
} finally {
if (generation !== requestGeneration) return;
rbStopProgress("license-progress");
results.setAttribute("aria-busy", "false");
submitBtns.forEach(b => {
b.disabled = false;
b.innerHTML = `🛡 <span>${rbText("Check Green OA policy")}</span>`;
});
}
});
}
function getLicenseData() {
const g = id => document.getElementById(id)?.value?.trim() || "";
return {
doi: RB_ROOT.dataset.rbShareMode === "journal" ? "" : g("l-doi"),
journal_name: RB_ROOT.dataset.rbShareMode === "article" ? "" : g("l-journal"),
issn: RB_ROOT.dataset.rbShareMode === "article" ? "" : g("l-issn"),
publisher: RB_ROOT.dataset.rbShareMode === "article" ? "" : g("l-publisher"),
manuscript_version: g("l-version"),
funder: g("l-funder"),
intended_repository: g("l-repo"),
intended_licence: g("l-licence"),
notes: g("l-notes"),
};
}
function renderPolicyCard(j, sourceMode, result) {
const oa = j.green_oa || {};
const policyHeading = sourceMode === "journal_api"
? "📚 Open Policy Finder options by article version"
: "🟢 Green OA / self-archiving by version";
const policyNotes = [
oa.licence_notes ? `<p><strong>Licence notes:</strong> ${esc(oa.licence_notes)}</p>` : "",
oa.repository_action_note ? `<p><strong>Repository action:</strong> ${esc(oa.repository_action_note)}</p>` : "",
oa.evidence_note ? `<p style="font-style:italic;font-size:12px;color:var(--text-muted)">Evidence: ${esc(oa.evidence_note)}</p>` : "",
oa.risk_flag ? `<p class="p-risk">[!] <span><strong>Risk:</strong> ${esc(oa.risk_flag)}</span></p>` : "",
].filter(Boolean).join("");
const vl = j.verify_links || {};
const licenseVerifyLinks = {
sherpa_romeo: vl.sherpa_romeo,
doaj: vl.doaj,
scopus: vl.scopus,
openalex: vl.openalex,
};
return `
<div class="card j-card">
<div class="j-header">
<div class="j-meta">${esc(j.publisher || "")}${j.issn ? ` · ISSN ${esc(j.issn)}` : ""}</div>
<div class="j-title">${rbJournalTitle(j)}</div>${rbJournalLinks(j)}
<div class="badge-row">
${provenanceBadge(oa, sourceMode)}
</div>
</div>
<div class="j-body">
<div>
<h5 style="font-size:14px;font-weight:600;margin-bottom:10px">${policyHeading}</h5>
${sourceMode === "journal" && oa.policy_status !== "Confirmed" ? `
<div class="policy-notes"><p><strong>No journal-level policy was retrieved.</strong> ${esc(result?.global_notes || "Use the linked Open Policy Finder search to check the current record.")}</p></div>` : `
<div class="version-list">
${renderVersionBlock("Submitted version / preprint", oa.preprint)}
${renderVersionBlock("Accepted manuscript (AAM / postprint)", oa.postprint)}
${renderVersionBlock("Published version (Version of Record)", oa.published_version)}
</div>`}
</div>
${rbRenderPolicyEvaluation(oa.policy_evaluation || result?.repository_recommendation?.policy_evaluation)}
${renderDepositStatement(oa)}
${policyNotes ? `<div class="policy-notes">${policyNotes}</div>` : ""}
${renderSourcePanel(oa, result)}
${renderVerifyLinks(licenseVerifyLinks, false)}
</div>
</div>`;
}
function renderDepositRecommendation(r) {
if (!r) return "";
return `
<div class="card rec-card mt-6">
<div class="card-header"><h2>📦 Repository deposit recommendation</h2></div>
<div class="card-body space-y">
<dl class="rec-grid">
${r.permission_status ? `<div class="rec-item"><dt>Permission</dt><dd>${esc(r.permission_status)}</dd></div>` : ""}
${r.embargo_status ? `<div class="rec-item"><dt>Embargo status</dt><dd>${esc(r.embargo_status)}</dd></div>` : ""}
<div class="rec-item"><dt>Best version to deposit</dt><dd>${esc(r.best_version_to_deposit)}</dd></div>
<div class="rec-item"><dt>Best timing</dt><dd>${esc(r.best_timing)}</dd></div>
<div class="rec-item"><dt>Immediate open deposit</dt><dd>${esc(r.immediate_open_deposit_possible)}</dd></div>
<div class="rec-item"><dt>Embargoed deposit needed</dt><dd>${esc(r.embargoed_deposit_needed)}</dd></div>
<div class="rec-item"><dt>Metadata-only first</dt><dd>${esc(r.metadata_only_first)}</dd></div>
</dl>
${r.khazna_note ? `<div class="policy-notes"><p><strong>Khazna note:</strong> ${esc(r.khazna_note)}</p></div>` : ""}
${r.manual_checks_required?.length ? `
<div>
<h5 style="font-size:13px;font-weight:600;margin-bottom:6px">[!] Manual checks required</h5>
<ul class="checks-list">${r.manual_checks_required.map(c => `<li>${esc(c)}</li>`).join("")}</ul>
</div>` : ""}
</div>
</div>`;
}
function renderLicenseResults(result, container) {
const journals = result.journals || [];
const sourceMode = result.source_mode || "journal";
const firstOA = journals[0]?.green_oa || {};
const intro = sourceMode === "doi"
? "Here are your verified self-archiving rights for this article."
: sourceMode === "journal_api"
? "Here are the journal-level policy options retrieved from the authenticated Jisc Open Policy Finder API. Select the option that applies before depositing."
: "I could not retrieve a policy summary for this journal — here is what to check.";
container.innerHTML = `
${renderMascotRow(intro)}
<div class="results-header">
<h2 class="results-title">Policy result</h2>
<div class="results-meta">
<button class="btn btn-ghost" id="license-reset">↩ Start over</button>
</div>
</div>
<h3 style="font-family:Georgia,serif;font-size:20px;margin-bottom:14px">🟢 Green OA / self-archiving by version</h3>
${journals.map(j => renderPolicyCard(j, sourceMode, result)).join("")}
${renderKhaznaStatus(result.khazna_status)}
${renderDepositRecommendation(result.repository_recommendation)}
${renderShareYourPaper(result, firstOA)}
${renderSubjectRepositories(result.subject_repositories)}
${result.khazna ? renderKhaznaCard(result.khazna, "article") : ""}
${renderNextActions(result.next_actions, result.global_notes)}
${renderHelpCard()}
`;
document.getElementById("license-reset")?.addEventListener("click", () => {
container.innerHTML = "";
container.classList.add("hidden");
document.getElementById("license-progress")?.classList.remove("show");
document.getElementById("license-form")?.reset();
const dEl = document.getElementById("l-doi"); if (dEl) dEl.value = "";
document.getElementById("journal-lookup-wrap") && (document.getElementById("journal-lookup-wrap").innerHTML = "");
RB_ROOT.scrollIntoView({ behavior: "smooth", block: "start" });
});
wireCopyButtons(container);
container.scrollIntoView({ behavior: "smooth", block: "start" });
}
/* ------------------------------------------------------------------ */
// repository.js - Data repository tab
function repositoryTab() {
const form = document.getElementById("repo-form");
const results = document.getElementById("repo-results");
if (!form) return;
let requestGeneration = 0;
form.addEventListener("reset", () => {
requestGeneration += 1;
rbCancelRequest("repository");
rbResetFormUi("repo");
});
form.addEventListener("submit", async (e) => {
e.preventDefault();
const generation = ++requestGeneration;
const submitBtn = form.querySelector('.btn-primary[type="submit"]');
submitBtn.disabled = true;
submitBtn.innerHTML = ` Finding repositories...`;
results.innerHTML = "";
results.classList.remove("hidden");
showProgress("repo-progress", [
"Analysing your dataset...",
"Matching repositories...",
"Building recommendations..."
], { requestKey: "repository" });
try {
const dataset = getDatasetData();
setStep("repo-progress", 1);
const data = await callAPI("/api/find-repository", { dataset, model: getModel(), language: getLanguage() }, { requestKey: "repository" });
if (generation !== requestGeneration) return;
setStep("repo-progress", 2);
doneProgress("repo-progress", `[OK] Repository search complete`);
renderRepoResults(data.result, results);
rbApplyUiLanguage(results);
} catch (err) {
if (generation !== requestGeneration || rbStaleRequest(err)) return;
failProgress("repo-progress", err);
} finally {
if (generation !== requestGeneration) return;
rbStopProgress("repo-progress");
submitBtn.disabled = false;
submitBtn.innerHTML = `<span id="btn-repo-submit">${rbText("Find best repositories")}</span>`;
results.setAttribute("aria-busy", "false");
}
});
}
function getDatasetData() {
const g = id => document.getElementById(id)?.value?.trim() || "";
return {
title: g("r-title"),
description: g("r-desc"),
discipline: g("r-discipline"),
data_types: g("r-datatypes"),
file_formats: g("r-formats"),
approx_size: g("r-size"),
sensitivity: g("r-sensitivity"),
contains_personal_data: g("r-personal"),
licence_intent: g("r-licence"),
funder: g("r-funder"),
institution: g("r-institution"),
country: g("r-country"),
needs_doi: g("r-doi"),
needs_versioning: g("r-versioning"),
embargo_required: g("r-embargo"),
embargo_months: g("r-embargo") === "Yes" && g("r-embargo-months") ? Number(g("r-embargo-months")) : null,
preferred_repository: g("r-preferred"),
related_publication: g("r-publication"),
notes: g("r-notes"),
};
}
function renderDatasetUnderstanding(d) {
if (!d) return "";
return `
<div class="card understanding">
<div class="card-header"><h2>🗂 Dataset understanding</h2></div>
<div class="card-body">
<p style="font-size:14px">${esc(d.summary)}</p>
<div class="tag-row">
${d.discipline ? `<span class="badge b-primary">${esc(d.discipline)}</span>` : ""}
<span class="badge b-muted">Sensitivity: ${esc(d.sensitivity_assessment)}</span>
${(d.data_types || []).map(t => `<span class="badge b-muted">${esc(t)}</span>`).join("")}
</div>
${d.inferred_requirements?.length ? `
<div>
<h5 style="font-size:13px;font-weight:600;margin-bottom:6px">Inferred requirements</h5>
<ul style="list-style:disc;padding-left:18px;display:flex;flex-direction:column;gap:3px">
${d.inferred_requirements.map(r => `<li style="font-size:13px;color:var(--text-muted)">${esc(r)}</li>`).join("")}
</ul>
</div>` : ""}
${d.assumptions?.length ? `
<div>
<h5 style="font-size:13px;font-weight:600;margin-bottom:6px">Assumptions made</h5>
<ul style="list-style:disc;padding-left:18px;display:flex;flex-direction:column;gap:3px">
${d.assumptions.map(a => `<li style="font-size:13px;color:var(--text-muted)">${esc(a)}</li>`).join("")}
</ul>
</div>` : ""}
</div>
</div>`;
}
function renderDepositStrategy(s) {
if (!s) return "";
return `
<div class="card rec-card mt-6">
<div class="card-header"><h2> Deposit strategy</h2></div>
<div class="card-body space-y">
${s.selection_status === "no_verified_destination" ? `<p class="policy-notes"><strong>${esc(rbText("No destination is verified for file deposit. Review the requirements with KU Library."))}</strong></p>` : s.selection_status === "candidates_require_review" ? `<p class="policy-notes">${esc(rbText("Candidate repositories need manual review before depositing files."))}</p>` : ""}
<dl class="rec-grid">
<div class="rec-item"><dt>Primary choice</dt><dd>${rbTrustedAnchor(s.primary_url, s.primary_choice)} ${s.primary_url ? rbTrustedAnchor(s.primary_url, rbText("Visit repository"), "btn btn-ghost") : ""}</dd></div>
<div class="rec-item"><dt>Secondary choice</dt><dd>${rbTrustedAnchor(s.secondary_url, s.secondary_choice)} ${s.secondary_url ? rbTrustedAnchor(s.secondary_url, rbText("Visit repository"), "btn btn-ghost") : ""}</dd></div>
<div class="rec-item" style="grid-column:1/-1"><dt>Metadata standard</dt><dd>${esc(s.metadata_standard)}</dd></div>
</dl>
${s.khazna_metadata_note ? `
<div class="khazna-tip" style="background:var(--primary-xlight);border-color:var(--primary-light)">
<span>️</span><span style="color:var(--primary)">${esc(s.khazna_metadata_note)}</span>
</div>` : ""}
${s.deposit_workflow?.length ? `
<div>
<h5 style="font-size:13px;font-weight:600;margin-bottom:6px">🔄 Deposit workflow</h5>
<ol style="list-style:decimal;padding-left:18px;display:flex;flex-direction:column;gap:4px">
${s.deposit_workflow.map(w => `<li style="font-size:13px;color:var(--text-muted)">${esc(w)}</li>`).join("")}
</ol>
</div>` : ""}
${s.manual_checks_required?.length ? `
<div>
<h5 style="font-size:13px;font-weight:600;margin-bottom:6px">[!] Manual checks required</h5>
<ul class="checks-list">${s.manual_checks_required.map(c => `<li>${esc(c)}</li>`).join("")}</ul>
</div>` : ""}
</div>
</div>`;
}
function rbRenderRepositoryExclusions(exclusions) {
const rows = Array.isArray(exclusions) ? exclusions.filter(item => item && item.name).slice(0, 20) : [];
if (!rows.length) return "";
return `<details class="policy-notes rb-repository-exclusions"><summary>${esc(rbText("Candidates excluded by requirement checks"))}</summary>
<p>${esc(rbText("These candidates were removed from the recommendations after checking your requirements. Review the reasons when refining your search."))}</p>
<ul class="checks-list">${rows.map(item => {
const reasons = Array.isArray(item.reasons) ? item.reasons : [];
const unresolved = Array.isArray(item.unresolved_constraints) ? item.unresolved_constraints : [];
return `<li><strong>${esc(item.name)}</strong>${reasons.length ? `: ${reasons.slice(0, 8).map(esc).join("; ")}` : ""}${unresolved.length ? `<p>${esc(rbText("Still unverified:"))} ${unresolved.slice(0, 8).map(esc).join("; ")}</p>` : ""}</li>`;
}).join("")}</ul></details>`;
}
function rbRe3dataSearchUrl(query) {
const text = String(query || "").trim();
return text ? `https://www.re3data.org/search?query=${encodeURIComponent(text)}` : "https://www.re3data.org";
}
function rbRenderRe3dataSupplement(supplement) {
if (!supplement || typeof supplement !== "object") return "";
const status = String(supplement.status || "");
if (!status || status === "skipped" || status === "disabled") return "";
const query = String(supplement.query || "");
const searchLink = `<a href="${esc(safeHttpsUrl(rbRe3dataSearchUrl(query), ["re3data.org"]))}" target="_blank" rel="noopener noreferrer" class="vlink">${esc(rbText("Search re3data.org yourself"))} ↗</a>`;
const repos = Array.isArray(supplement.repositories) ? supplement.repositories.filter(item => item && item.name).slice(0, 8) : [];
if (status !== "ok" || !repos.length) {
const message = supplement.message || rbText("No additional re3data repositories were found.");
return `<div class="policy-notes rb-re3data-note"><p>${esc(message)}</p><p>${searchLink}</p></div>`;
}
const list = value => Array.isArray(value) ? value.filter(Boolean).map(String).join(", ") : String(value || "");
const items = repos.map(repo => {
const specs = [
["Subjects", list(repo.subjects)],
["Persistent ID", repo.persistent_identifier],
["Data upload", repo.data_upload],
["Data access", repo.data_access],
["Versioning", repo.versioning],
["Certificates", list(repo.certificates)],
["Country", list(repo.countries)],
].filter(([, value]) => String(value || "").trim());
const notes = Array.isArray(repo.review_notes) ? repo.review_notes.filter(Boolean).slice(0, 4) : [];
const record = safeHttpsUrl(repo.re3data_url, ["re3data.org"]);
const site = safeHttpsUrl(repo.url);
return `<article class="rb-re3data-item">
<h4>${rbTrustedAnchor(repo.url, repo.name)}</h4>
${repo.description ? `<p style="color:var(--text-muted)">${esc(repo.description)}</p>` : ""}
${specs.length ? `<dl class="r-specs">${specs.map(([label, value]) => `<div><dt>${esc(rbText(label))}</dt><dd>${esc(value)}</dd></div>`).join("")}</dl>` : ""}
${notes.length ? `<ul class="checks-list">${notes.map(note => `<li>${esc(note)}</li>`).join("")}</ul>` : ""}
<div class="verify-row">
${site ? `<a href="${esc(site)}" target="_blank" rel="noopener noreferrer" class="vlink">${esc(rbText("Visit repository"))} ↗</a>` : ""}
${record ? `<a href="${esc(record)}" target="_blank" rel="noopener noreferrer" class="vlink">${esc(rbText("re3data record"))} ↗</a>` : ""}
</div>
${repo.source_note ? `<p style="font-size:12px;color:var(--text-muted)">${esc(repo.source_note)}</p>` : ""}
</article>`;
}).join("");
const open = supplement.recommended_view === "expanded" ? " open" : "";
return `<details class="rb-re3data"${open}>
<summary>${esc(rbText("More repositories from re3data.org"))} (${repos.length})<span class="rb-re3data-tag">${esc(rbText("Not reviewed by KU Library"))}</span></summary>
<div class="rb-re3data-body">
<p class="rb-re3data-intro">${esc(supplement.message || "")} ${esc(rbText("The recommendations above come from the KU Library curated registry; use these listings to widen your options and confirm every detail with the repository."))}</p>
${items}
<p style="margin-top:10px">${searchLink}</p>
</div>
</details>`;
}
function renderRepoResults(result, container) {
const repos = result.repositories || [];
container.innerHTML = `
${renderMascotRow(esc(rbText('Here are repository options and the requirement checks for your dataset.')))}
<div class="results-header">
<h2 class="results-title">Recommended repositories</h2>
<div class="results-meta">
<span class="count-chip">${repos.length} repositories</span>
<button class="btn btn-ghost" id="repo-reset"> Start over</button>
</div>
</div>
${renderDatasetUnderstanding(result.dataset_understanding)}
<h3 style="font-family:Georgia,serif;font-size:22px;margin:20px 0 14px"> Recommended repositories</h3>
${repos.map((r, i) => renderRepoCard(r, i)).join("")}
${rbRenderRe3dataSupplement(result.re3data_supplement)}
${renderDepositStrategy(result.deposit_strategy)}
${rbRenderRepositoryExclusions(result.selection_exclusions)}
${renderNextActions(result.next_actions, result.global_notes)}
${renderHelpCard()}
`;
document.getElementById("repo-reset")?.addEventListener("click", () => {
container.innerHTML = "";
container.classList.add("hidden");
document.getElementById("repo-progress")?.classList.remove("show");
document.getElementById("repo-form")?.reset();
RB_ROOT.scrollIntoView({ behavior: "smooth", block: "start" });
});
container.scrollIntoView({ behavior: "smooth", block: "start" });
}
/* ------------------------------------------------------------------ */
// app.js - tab router, language selector, progress helpers, chat widget
const RB_CHAT_BASE = "https://nikeshn-researchbee.hf.space";
// ── Mode switcher ──────────────────────────────────────────────────────────
function rbFocusWorkflow(element) {
if (!element) return;
if (!element.hasAttribute("tabindex")) element.setAttribute("tabindex", "-1");
element.focus({ preventScroll: true });
element.scrollIntoView({ behavior: "auto", block: "start" });
}
function rbUpdateDataNotice() {
const hasForm = (RB_ROOT.dataset.rbView === "license" && Boolean(RB_ROOT.dataset.rbShareMode))
|| (RB_ROOT.dataset.rbView === "data" && Boolean(RB_ROOT.dataset.rbRepoStep))
|| (RB_ROOT.dataset.rbView === "journals" && Boolean(RB_ROOT.dataset.rbMode));
const notice = document.getElementById("rb-data-notice");
if (notice) notice.hidden = !hasForm;
}
function switchMode(mode, focus = false) {
const selectedMode = ["subject", "manuscript"].includes(mode) ? mode : "";
RB_ROOT.dataset.rbMode = selectedMode;
RB_ROOT.querySelectorAll(".mode-btn").forEach(button => {
const selected = button.dataset.mode === selectedMode;
button.classList.toggle("active", selected);
button.setAttribute("aria-expanded", String(selected));
button.tabIndex = 0;
});
["subject", "manuscript"].forEach(name => {
const panel = document.getElementById(`mode-${name}`);
if (panel) { panel.hidden = name !== selectedMode; panel.style.display = name === selectedMode ? "block" : "none"; }
});
const choices = document.getElementById("rb-journal-choices");
if (choices) choices.hidden = Boolean(selectedMode);
const back = document.getElementById("rb-mode-back");
if (back) back.hidden = !selectedMode;
rbUpdateDataNotice();
if (focus) rbFocusWorkflow(selectedMode
? document.querySelector(`#mode-${selectedMode} .card-header h2`)
: document.getElementById("rb-journal-choice-title"));
}
window.ResearchBee.switchMode = switchMode;
function activateTab(target, focus = false) {
const selectedTab = ["journals", "license", "data"].includes(target) ? target : "home";
RB_ROOT.dataset.rbView = selectedTab;
RB_ROOT.querySelectorAll(".tab-btn").forEach((button, index) => {
const selected = button.dataset.tab === selectedTab;
button.classList.toggle("active", selected);
button.setAttribute("aria-selected", String(selected));
button.tabIndex = selected || (selectedTab === "home" && index === 0) ? 0 : -1;
});
RB_ROOT.querySelectorAll(".tab-panel").forEach(panel => {
const selected = panel.id === `tab-${selectedTab}`;
panel.classList.toggle("active", selected);
panel.hidden = !selected; panel.style.display = selected ? "block" : "none";
});
const home = document.getElementById("rb-home-view");
if (home) home.hidden = selectedTab !== "home";
if (selectedTab === "journals" || selectedTab === "home") switchMode("");
if (selectedTab === "license" || selectedTab === "home") rbShowShareChoices(false);
if (selectedTab === "data" || selectedTab === "home") rbShowRepositoryIntro(false);
rbUpdateDataNotice();
if (focus) rbFocusWorkflow(selectedTab === "journals"
? document.getElementById("rb-journal-choice-title")
: selectedTab === "license" ? document.getElementById("rb-share-choice-title")
: document.getElementById("rb-repo-intro-title"));
}
function rbShowHome(focus = false) {
activateTab("home");
if (focus) rbFocusWorkflow(document.getElementById("rb-functions-title"));
}
window.ResearchBee.activateTab = activateTab;
RB_ROOT.querySelectorAll(".tab-btn").forEach(btn => {
btn.addEventListener("click", () => activateTab(btn.dataset.tab, true));
});
document.getElementById("rb-back-options")?.addEventListener("click", () => switchMode("", true));
// ── Language selector ──────────────────────────────────────────────────────
const TRANSLATIONS = {
"lbl-title": { en: "Title", ar: "العنوان" },
"lbl-abstract": { en: "Abstract", ar: "الملخص" },
"lbl-keywords": { en: "Keywords (comma-separated)", ar: "الكلمات المفتاحية (مفصولة بفاصلة)" },
"lbl-discipline": { en: "Discipline / sub-discipline", ar: "التخصص / الفرع العلمي" },
"lbl-article-type": { en: "Article type", ar: "نوع المقالة" },
"lbl-methods": { en: "Methods (brief)", ar: "المنهجية (موجزة)" },
"lbl-oa-pref": { en: "OA preference", ar: "تفضيل الوصول المفتوح" },
"lbl-apc": { en: "APC budget", ar: "ميزانية رسوم النشر" },
"lbl-ranking-pref": { en: "Ranking filter", ar: "تصفية حسب التصنيف" },
"lbl-ranking-src": { en: "Ranking source", ar: "مصدر التصنيف" },
"lbl-speed": { en: "Publication speed", ar: "سرعة النشر" },
"lbl-repo-target": { en: "Repository target", ar: "المستودع المستهدف" },
"lbl-funder": { en: "Funder", ar: "الجهة الممولة" },
"lbl-institution": { en: "Institution", ar: "المؤسسة" },
"lbl-country": { en: "Country / region", ar: "الدولة / المنطقة" },
"lbl-audience": { en: "Target audience", ar: "الجمهور المستهدف" },
"lbl-preferred": { en: "Preferred journals (optional)", ar: "المجلات المفضلة (اختياري)" },
"lbl-avoid": { en: "Journals to avoid (optional)", ar: "المجلات المراد تجنبها (اختياري)" },
"btn-journal-submit": { en: "Find best-fit journals", ar: "ابحث عن أفضل المجلات الملائمة" },
"lbl-subject": { en: "Subject / discipline", ar: "الموضوع / التخصص" },
"btn-subject-submit": { en: "Search journals", ar: "ابحث عن مجلات" },
"lbl-l-journal": { en: "Journal name", ar: "اسم المجلة" },
"lbl-l-issn": { en: "ISSN (optional)", ar: "الرقم الدولي ISSN (اختياري)" },
"lbl-l-publisher": { en: "Publisher (optional)", ar: "الناشر (اختياري)" },
"lbl-l-version": { en: "Manuscript version of interest", ar: "نسخة المخطوطة المطلوبة" },
"lbl-l-funder": { en: "Funder (affects rights retention)", ar: "الجهة الممولة (تؤثر على حقوق الاحتفاظ)" },
"lbl-l-repo": { en: "Intended deposit location", ar: "موقع الإيداع المقصود" },
"lbl-l-licence": { en: "Intended licence", ar: "الرخصة المقصودة" },
"lbl-l-notes": { en: "Additional context (optional)", ar: "سياق إضافي (اختياري)" },
"btn-license-submit": { en: "Check Green OA policy", ar: "تحقق من سياسة الوصول المفتوح الأخضر" },
"lbl-r-title": { en: "Dataset title", ar: "عنوان مجموعة البيانات" },
"lbl-r-desc": { en: "Description", ar: "الوصف" },
"lbl-r-discipline": { en: "Discipline / domain", ar: "التخصص / المجال" },
"lbl-r-datatypes": { en: "Data types", ar: "أنواع البيانات" },
"lbl-r-formats": { en: "File formats", ar: "صيغ الملفات" },
"lbl-r-size": { en: "Approximate total size", ar: "الحجم الإجمالي التقريبي" },
"lbl-r-sensitivity": { en: "Sensitivity classification", ar: "تصنيف الحساسية" },
"lbl-r-personal": { en: "Contains personal / health data?", ar: "يحتوي على بيانات شخصية / صحية؟" },
"lbl-r-licence": { en: "Intended licence", ar: "الرخصة المقصودة" },
"lbl-r-embargo": { en: "Embargo required?", ar: "هل يلزم حظر نشر؟" },
"lbl-r-doi": { en: "Persistent identifier (DOI) required?", ar: "هل يلزم معرف دائم (DOI)؟" },
"lbl-r-versioning": { en: "Versioning required?", ar: "هل يلزم إدارة الإصدارات؟" },
"lbl-r-funder": { en: "Funder", ar: "الجهة الممولة" },
"lbl-r-institution": { en: "Institution", ar: "المؤسسة" },
"lbl-r-country": { en: "Country / region", ar: "الدولة / المنطقة" },
"lbl-r-preferred": { en: "Preferred / required repository (optional)", ar: "المستودع المفضل / المطلوب (اختياري)" },
"lbl-r-publication": { en: "Linked publication / DOI (optional)", ar: "المنشور المرتبط / DOI (اختياري)" },
"lbl-r-notes": { en: "Additional notes", ar: "ملاحظات إضافية" },
"btn-repo-submit": { en: "Find best repositories", ar: "ابحث عن أفضل المستودعات" },
};
const PLACEHOLDERS = {
"j-title": { en: "Full manuscript title", ar: "عنوان المخطوطة كاملاً" },
"j-abstract": { en: "Paste your full abstract here...", ar: "الصق ملخصك الكامل هنا..." },
"j-keywords": { en: "e.g. machine learning, library, open access", ar: "مثال: تعلم آلي، مكتبة، وصول مفتوح" },
"j-discipline": { en: "e.g. Library and Information Science", ar: "مثال: علم المكتبات والمعلومات" },
"j-methods": { en: "e.g. survey, experiment, case study", ar: "مثال: مسح، تجربة، دراسة حالة" },
"j-apc": { en: "e.g. up to USD 2000, or no APC", ar: "مثال: حتى 2000 دولار، أو بدون رسوم" },
"j-funder": { en: "e.g. ERC, NIH, Wellcome", ar: "مثال: المجلس الأوروبي للبحوث، NIH" },
"j-institution": { en: "e.g. Khalifa University", ar: "مثال: جامعة خليفة" },
"j-country": { en: "e.g. UAE", ar: "مثال: الإمارات العربية المتحدة" },
"j-audience": { en: "e.g. library practitioners, AI researchers", ar: "مثال: أمناء المكتبات، باحثو الذكاء الاصطناعي" },
"j-preferred": { en: "e.g. Nature Communications, PLOS ONE", ar: "مثال: Nature Communications، PLOS ONE" },
"j-avoid": { en: "Journals to exclude from recommendations", ar: "المجلات المراد استبعادها من التوصيات" },
"s-subject": { en: "e.g. Petroleum Engineering, Machine Learning...", ar: "مثال: هندسة البترول، تعلم آلي..." },
"l-journal": { en: "e.g. Nature Communications", ar: "مثال: Nature Communications" },
"l-issn": { en: "e.g. 2041-1723", ar: "مثال: 2041-1723" },
"l-publisher": { en: "e.g. Springer Nature", ar: "مثال: Springer Nature" },
"l-funder": { en: "e.g. cOAlition S, ERC, NIH", ar: "مثال: تحالف S، المجلس الأوروبي للبحوث" },
"l-notes": { en: "Already accepted? Embargo concerns?", ar: "هل تم قبولها؟ مخاوف بشأن الحظر؟" },
"r-title": { en: "Descriptive title for your dataset", ar: "عنوان وصفي لمجموعة بياناتك" },
"r-desc": { en: "What does the dataset contain?", ar: "ماذا تحتوي مجموعة البيانات؟" },
"r-discipline": { en: "e.g. genomics, climate science", ar: "مثال: علم الجينوم، علوم المناخ" },
"r-datatypes": { en: "e.g. tabular, images, time series", ar: "مثال: جداول، صور، سلاسل زمنية" },
"r-formats": { en: "e.g. CSV, FASTQ, NetCDF, TIFF", ar: "مثال: CSV، FASTQ، NetCDF" },
"r-size": { en: "e.g. 250 MB / 5 GB / 2 TB", ar: "مثال: 250 ميغابايت / 5 جيجابايت" },
"r-funder": { en: "e.g. Horizon Europe, NIH, ADEK", ar: "مثال: أفق أوروبا، NIH، أديك" },
"r-institution": { en: "e.g. Khalifa University", ar: "مثال: جامعة خليفة" },
"r-country": { en: "e.g. UAE", ar: "مثال: الإمارات العربية المتحدة" },
"r-preferred": { en: "e.g. Zenodo, GenBank", ar: "مثال: Zenodo، GenBank" },
"r-publication": { en: "Related article DOI or title", ar: "DOI أو عنوان المقالة المرتبطة" },
"r-notes": { en: "Any special requirements...", ar: "أي متطلبات خاصة..." },
};
function applyLanguage(lang) {
const isAr = lang === "arabic";
RB_ROOT.lang = isAr ? "ar" : "en";
RB_ROOT.dir = isAr ? "rtl" : "ltr";
window.ResearchBee.chatLang = lang;
Object.entries(PLACEHOLDERS).forEach(([id, text]) => {
const element = document.getElementById(id);
if (element) element.placeholder = isAr ? text.ar : text.en;
});
RB_ROOT.querySelectorAll("input[type=text], textarea").forEach(element => { element.dir = ["l-doi", "l-issn"].includes(element.id) ? "ltr" : "auto"; });
RB_ROOT.querySelectorAll(".lang-btn").forEach(button => button.setAttribute("aria-pressed", String(button.dataset.lang === lang)));
let banner = document.getElementById("ar-instruction-banner");
if (!banner) {
banner = document.createElement("div"); banner.id = "ar-instruction-banner"; banner.className = "ar-banner";
RB_ROOT.querySelector(".main-content")?.prepend(banner);
}
banner.hidden = !isAr;
banner.textContent = "وضع العربية: تظهر تسميات الواجهة وإجابات الذكاء الاصطناعي بالعربية. تبقى أسماء المجلات وبيانات المصادر وشروط السياسات بلغتها الأصلية للتحقق منها.";
["j-preferred", "j-avoid", "s-preferred", "s-avoid"].forEach(id => { const field = document.getElementById(id); if (field) field.placeholder = isAr ? "اسم مجلة واحد في كل سطر؛ تبقى الفواصل داخل العناوين كما هي" : "One journal title per line; commas within titles are preserved"; });
rbApplyUiLanguage(RB_ROOT);
}
RB_ROOT.querySelectorAll(".lang-btn").forEach(btn => {
btn.addEventListener("click", () => {
RB_ROOT.querySelectorAll(".lang-btn").forEach(b => b.classList.remove("active"));
btn.classList.add("active");
applyLanguage(btn.dataset.lang);
});
});
// ── Progress helpers ───────────────────────────────────────────────────────
// The API returns one completed response; do not invent backend stage updates.
const RB_PROGRESS = new Map();
function rbStartWaiting(wrap, options = {}) {
const started = Date.now();
const status = document.createElement("div");
status.className = "rb-wait-status";
status.style.cssText = "font-size:13px;line-height:1.6";
const label = document.createElement("span");
label.setAttribute("role", "status"); label.setAttribute("aria-live", "polite");
const clock = document.createElement("span");
clock.style.cssText = "display:block;font-size:12px;opacity:.85";
clock.setAttribute("aria-hidden", "true"); // Avoid announcing every second.
status.append(label, clock);
wrap.appendChild(status);
let timer = null, stopped = false;
const stop = () => { stopped = true; clearTimeout(timer); cancel?.remove(); };
const cancel = options.onCancel ? document.createElement("button") : null;
if (cancel) {
cancel.type = "button"; cancel.className = "btn btn-ghost rb-wait-cancel";
cancel.style.cssText = "margin-top:8px;padding:6px 12px;font-size:12px";
cancel.textContent = rbWaitText("Cancel waiting", "إلغاء الانتظار");
cancel.addEventListener("click", () => {
const restoreFocus = cancel.contains(document.activeElement);
stop(); options.onCancel();
if (restoreFocus) options.focusTarget?.()?.focus();
});
status.appendChild(cancel);
}
const update = () => {
if (stopped) return;
const seconds = Math.max(0, Math.floor((Date.now() - started) / 1000));
const receiving = options.receiving?.();
const message = receiving
? rbWaitText("Receiving your reply…", "جارٍ استلام الرد…")
: seconds >= 60
? rbWaitText("Still waiting for the service. You can cancel waiting and try again; your entries will be kept.", "ما زلنا ننتظر الخدمة. يمكنك إلغاء الانتظار والمحاولة مرة أخرى؛ سيتم الاحتفاظ بمدخلاتك.")
: seconds >= 20
? rbWaitText("Still processing. ResearchBee or a data service may be starting up or busy.", "لا تزال المعالجة جارية. قد تكون ResearchBee أو إحدى خدمات البيانات قيد التشغيل أو مشغولة.")
: rbWaitText("Request sent. Waiting for ResearchBee and its data services…", "تم إرسال الطلب. جارٍ انتظار ResearchBee وخدمات البيانات…");
if (label.textContent !== message) label.textContent = message;
clock.textContent = rbWaitText(`Elapsed: ${seconds} seconds · maximum wait 2 minutes`, `الوقت المنقضي: ${seconds} ثانية · أقصى انتظار دقيقتان`);
timer = setTimeout(update, 1000);
};
update();
return { stop, remove: () => { stop(); status.remove(); } };
}
function rbStopProgress(containerId) {
RB_PROGRESS.get(containerId)?.stop();
RB_PROGRESS.delete(containerId);
document.getElementById(containerId.replace("-progress", "-results"))?.setAttribute("aria-busy", "false");
}
function showProgress(containerId, _steps, options = {}) {
rbStopProgress(containerId);
const wrap = document.getElementById(containerId);
if (!wrap) return;
wrap.replaceChildren();
wrap.classList.add("show");
wrap.setAttribute("role", "status");
document.getElementById(containerId.replace("-progress", "-results"))?.setAttribute("aria-busy", "true");
RB_PROGRESS.set(containerId, rbStartWaiting(wrap, {
focusTarget: () => document.getElementById(containerId.replace("-progress", "-form"))?.querySelector("input, textarea, select"),
onCancel: options.requestKey ? () => {
rbCancelRequest(options.requestKey, true);
doneProgress(containerId, rbWaitText("Stopped waiting. Your entries are preserved. You can try again.", "تم إيقاف الانتظار. تم الاحتفاظ بمدخلاتك ويمكنك المحاولة مرة أخرى."));
} : null,
}));
}
function setStep(_containerId, _idx) { /* Kept for legacy callers; no simulated stages. */ }
function doneProgress(containerId, message) {
rbStopProgress(containerId);
const wrap = document.getElementById(containerId);
if (!wrap) return;
wrap.replaceChildren();
const label = document.createElement("div");
label.className = "p-step done"; label.textContent = message || rbWaitText("Complete", "اكتمل");
wrap.appendChild(label);
}
function hideProgress(containerId) {
rbStopProgress(containerId);
document.getElementById(containerId)?.classList.remove("show");
}
function failProgress(containerId, error) {
doneProgress(containerId, error?.message || rbWaitText("The request could not be completed. Please try again.", "تعذر إكمال الطلب. يرجى المحاولة مرة أخرى."));
document.getElementById(containerId)?.setAttribute("role", error?.cancelled ? "status" : "alert");
}
// ── Clipboard helper ───────────────────────────────────────────────────────
window.ResearchBee.copyToClipboard = function(text, el) {
navigator.clipboard.writeText(text).then(() => {
const orig = el.innerHTML;
el.innerHTML = "Copied!";
setTimeout(() => { el.innerHTML = orig; }, 1500);
});
};
// ── Chat widget ────────────────────────────────────────────────────────────
(function initChat() {
const MAX_HIST = 20;
const WELCOME = "Hi! I'm ResearchBee, Khalifa University Library's publishing and research-data assistant.\n\nI can explain how to choose and verify journals, interpret CiteScore, quartiles and impact indicators, understand KU Open Access and APC support, check article-sharing rights, and make research-data management and repository decisions. Use the three tools for structured results, or ask me to explain any publishing step.\n\nWhat would you like help with?";
const EXAMPLE_CHIPS = [
"How do I choose the best journal?",
"What does Q1 or CiteScore percentile mean?",
"Does KU cover my APC?",
"How do I choose a data repository?",
];
const MENU_CARDS = [
{
emoji: "🏆", color: "#1a2744", route: "journals", prefill: {},
title: "Find the best journal for my paper",
desc: "AI-matched journals with verified metrics and cover-letter support",
},
{
emoji: "🛡️", color: "#059669", route: "license", prefill: {},
title: "Deposit my article to Khazna or other repositories",
desc: "Check self-archiving rights, embargo & allowed versions",
},
{
emoji: "🗄️", color: "#d97706", route: "data", prefill: {},
title: "Find the right repository for my dataset",
desc: "Match your data to domain-specific & institutional repos",
},
{
emoji: "💬", color: "#4338CA", route: null, prefill: {},
title: "Other publishing questions",
desc: "KU OA policy, APC funding, publisher agreements & more",
},
];
const TAB_META = {
journals: { emoji: "📰", label: "Open Journal Submission tool", color: "#1a2744" },
license: { emoji: "🛡️", label: "Open License Checker", color: "#059669" },
data: { emoji: "🗄️", label: "Open Data Repository tool", color: "#d97706" },
};
let isOpen = false, isTyping = false, history = [];
let chatController = null, chatGeneration = 0, chatReturnFocus = null, chatWait = null, chatTimer = null;
let chatHintTimer = null, chatHintHideTimer = null;
const panel = document.getElementById("rb-chat-panel");
const launcher = document.getElementById("rb-chat-launcher");
const closeBtn = document.getElementById("rb-chat-close");
const msgs = document.getElementById("rb-chat-messages");
const input = document.getElementById("rb-chat-input");
const sendBtn = document.getElementById("rb-chat-send");
const badge = document.getElementById("rb-chat-badge");
const tooltip = document.getElementById("rb-chat-tooltip");
if (!panel || !launcher) return;
function getLang() {
return window.ResearchBee.chatLang
|| RB_ROOT.querySelector(".lang-btn.active")?.dataset.lang
|| "english";
}
function esc(str) {
return String(str || "")
.replace(/&/g,"&amp;").replace(/</g,"&lt;")
.replace(/>/g,"&gt;");
}
function scrollBottom() { msgs.scrollTop = msgs.scrollHeight; }
function addMessage(role, text) {
msgs.querySelector(".rb-menu-wrap")?.remove();
document.getElementById("rb-chips-wrap")?.remove();
const wrap = document.createElement("div");
wrap.className = `rb-msg ${role}`;
const bubble = document.createElement("div");
bubble.className = "rb-bubble";
rbRenderChatText(bubble, text);
wrap.appendChild(bubble);
msgs.appendChild(wrap);
scrollBottom();
}
function addRouteCTA(route, prefill) {
const meta = TAB_META[route];
if (!meta) return;
const wrap = document.createElement("div");
wrap.className = "rb-msg assistant";
const btn = document.createElement("button");
btn.className = "rb-route-btn";
btn.style.background = meta.color;
btn.innerHTML = `${meta.emoji} ${meta.label} →`;
btn.addEventListener("click", () => {
closePanel();
activateTabAndPrefill(route, prefill || {});
});
wrap.appendChild(btn);
msgs.appendChild(wrap);
scrollBottom();
}
function activateTabAndPrefill(route, prefill) {
activateTab(route);
if (route === "license" && (prefill.doi || prefill.journal_name || prefill.issn)) rbSetShareMode(prefill.doi ? "article" : "journal");
if (route === "data") rbSetRepositoryStep(1);
// Pre-fill fields
const FIELD_MAP = {
journals: { title: "j-title", abstract: "j-abstract", keywords: "j-keywords", discipline: "j-discipline", subject: "s-subject" },
license: { doi: "l-doi", journal_name: "l-journal", issn: "l-issn", publisher: "l-publisher" },
data: { title: "r-title", discipline: "r-discipline", data_types: "r-datatypes" },
};
const map = FIELD_MAP[route] || {};
Object.entries(prefill).forEach(([key, value]) => {
const elId = map[key];
if (!elId || !value) return;
const el = document.getElementById(elId);
if (el) el.value = value;
});
// Switch to correct mode for journals tab
if (route === "journals") {
switchMode(prefill.subject ? "subject" : "manuscript");
}
RB_ROOT.querySelector(".tabs-bar")?.scrollIntoView({ behavior: "smooth", block: "start" });
}
function showTyping() {
const wrap = document.createElement("div");
wrap.className = "rb-msg assistant";
wrap.id = "rb-typing-indicator";
wrap.innerHTML = '<div class="rb-typing"><span></span><span></span><span></span></div>';
msgs.appendChild(wrap);
scrollBottom();
}
function removeTyping() {
document.getElementById("rb-typing-indicator")?.remove();
}
function showExampleChips() {
if (document.getElementById("rb-chips-wrap")) return;
const wrap = document.createElement("div");
wrap.id = "rb-chips-wrap";
wrap.style.cssText = "display:flex;flex-wrap:wrap;gap:6px;padding:4px 14px 8px;";
EXAMPLE_CHIPS.forEach(text => {
const chip = document.createElement("button");
chip.style.cssText = "background:#f1f5f9;border:1px solid #e2e8f0;border-radius:20px;padding:5px 12px;font-family:system-ui,sans-serif;font-size:12px;color:#475569;cursor:pointer;transition:background .15s,border-color .15s;white-space:nowrap;";
chip.textContent = rbText(text);
chip.addEventListener("mouseover", () => { chip.style.background="#e0e7ff"; chip.style.borderColor="#4338CA"; chip.style.color="#4338CA"; });
chip.addEventListener("mouseout", () => { chip.style.background="#f1f5f9"; chip.style.borderColor="#e2e8f0"; chip.style.color="#475569"; });
chip.addEventListener("click", () => {
wrap.remove();
sendMessage(rbText(text));
});
wrap.appendChild(chip);
});
const inputArea = panel.querySelector(".rb-chat-input-wrap");
if (inputArea) panel.insertBefore(wrap, inputArea);
else msgs.appendChild(wrap);
}
function removeChips() {
document.getElementById("rb-chips-wrap")?.remove();
}
function rbResetChat(close = false) {
chatGeneration += 1;
chatController?.abort(); chatController = null;
chatWait?.remove(); chatWait = null;
clearTimeout(chatTimer); chatTimer = null;
clearTimeout(chatHintTimer); chatHintTimer = null;
clearTimeout(chatHintHideTimer); chatHintHideTimer = null;
isTyping = false; history = [];
msgs.replaceChildren();
input.value = ""; input.style.height = "auto";
sendBtn.disabled = true;
badge.classList.remove("visible"); tooltip.classList.remove("show");
document.getElementById("rb-clear-wrap")?.remove();
document.getElementById("rb-chips-wrap")?.remove();
if (close) closePanel();
else {
addMessage("assistant", getLang() === "arabic" ? RB_CHAT_WELCOME_AR : WELCOME);
showMenuCards();
}
}
window.ResearchBee.resetChat = () => rbResetChat(true);
// showMenuCards — chips only on welcome, clear button
function showMenuCards() {
showExampleChips();
const existing = document.getElementById("rb-clear-wrap");
if (existing) return;
const wrap = document.createElement("div");
wrap.id = "rb-clear-wrap";
wrap.style.cssText = "text-align:right;padding:0 14px 4px;";
const clearBtn = document.createElement("button");
clearBtn.className = "rb-clear-btn";
clearBtn.textContent = rbText("Clear");
clearBtn.addEventListener("click", () => rbResetChat(false));
wrap.appendChild(clearBtn);
const inputArea = panel.querySelector(".rb-chat-input-wrap");
if (inputArea) panel.insertBefore(wrap, inputArea);
scrollBottom();
}
function openPanel() {
chatReturnFocus = document.activeElement;
isOpen = true;
panel.hidden = false; panel.inert = false;
panel.classList.add("open");
panel.setAttribute("aria-hidden", "false");
launcher.setAttribute("aria-expanded", "true");
mobileBar?.setAttribute("aria-expanded", "true");
badge.classList.remove("visible");
tooltip.classList.remove("show");
input.focus();
if (!msgs.children.length) {
addMessage("assistant", getLang() === "arabic" ? RB_CHAT_WELCOME_AR : WELCOME);
showMenuCards();
}
}
function closePanel() {
isOpen = false;
panel.classList.remove("open");
panel.hidden = true; panel.inert = true;
if (panel.contains(document.activeElement)) (chatReturnFocus?.isConnected ? chatReturnFocus : launcher).focus();
panel.setAttribute("aria-hidden", "true");
launcher.setAttribute("aria-expanded", "false");
mobileBar?.setAttribute("aria-expanded", "false");
}
panel.hidden = true; panel.inert = true;
panel.addEventListener("keydown", event => { if (event.key === "Escape") { event.preventDefault(); closePanel(); } });
const mobileBar = document.getElementById("rb-mobile-chat-bar");
launcher.addEventListener("click", () => isOpen ? closePanel() : openPanel());
mobileBar?.addEventListener("click", () => isOpen ? closePanel() : openPanel());
closeBtn.addEventListener("click", closePanel);
document.addEventListener("click", (e) => {
const clickedMobileBar = mobileBar && mobileBar.contains(e.target);
if (isOpen && !panel.contains(e.target) && !launcher.contains(e.target) && !clickedMobileBar) {
closePanel();
}
});
input.addEventListener("input", () => {
input.style.height = "auto";
input.style.height = Math.min(input.scrollHeight, 100) + "px";
sendBtn.disabled = !input.value.trim() || isTyping;
});
input.addEventListener("keydown", (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
if (!sendBtn.disabled) sendMessage();
}
});
sendBtn.addEventListener("click", sendMessage);
async function sendMessage(presetText) {
const text = (typeof presetText === "string" ? presetText : input.value).trim();
if (!text || isTyping) return;
input.value = "";
input.style.height = "auto";
sendBtn.disabled = true;
isTyping = true;
addMessage("user", text);
history.push({ role: "user", content: text });
if (history.length > MAX_HIST) history = history.slice(-MAX_HIST);
// Create streaming bubble
msgs.querySelector(".rb-menu-wrap")?.remove();
document.getElementById("rb-chips-wrap")?.remove();
const wrap = document.createElement("div");
wrap.className = "rb-msg assistant";
const bubble = document.createElement("div");
bubble.className = "rb-bubble";
bubble.textContent = rbWaitText("Waiting for your reply…", "جارٍ انتظار الرد…");
wrap.appendChild(bubble);
msgs.appendChild(wrap);
scrollBottom();
let fullText = "";
const generation = ++chatGeneration;
const controller = new AbortController();
chatController = controller;
let cancelled = false, timedOut = false;
const waiting = rbStartWaiting(wrap, {
receiving: () => fullText.length > 0,
focusTarget: () => input,
onCancel: () => { cancelled = true; controller.abort(); },
});
chatWait = waiting;
const timer = setTimeout(() => { timedOut = true; controller.abort(); }, 120000);
chatTimer = timer;
try {
const res = await fetch(`${RB_CHAT_BASE}/api/chat`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages: rbPrepareChatHistory(history), language: getLang() }),
signal: controller.signal,
});
if (!res.ok) throw new Error(rbApiError(await res.json().catch(() => ({})), res.status));
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
let route = null;
let prefill = {};
let receivedFinal = false;
while (true) {
const { done, value } = await reader.read();
if (generation !== chatGeneration) return;
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n\n");
buffer = lines.pop(); // keep incomplete chunk
for (const line of lines) {
if (!line.startsWith("data: ")) continue;
let evt;
try { evt = JSON.parse(line.slice(6)); }
catch (_) { continue; } // Ignore malformed chunks; require a final event below.
if (evt.error) throw new Error(typeof evt.error === "string" ? evt.error : "The response was interrupted. Please try again.");
{
if (evt.done) {
receivedFinal = true;
// Final event — use clean reply from server
route = evt.route || null;
prefill = evt.prefill || {};
if (typeof evt.reply === "string") fullText = evt.reply;
else if (evt.token) fullText += evt.token;
} else if (evt.token) {
fullText += evt.token;
}
// Update bubble with current text
rbRenderChatText(bubble, fullText, !evt.done);
scrollBottom();
}
}
}
if (!receivedFinal) throw new Error("The response was interrupted. Please try again.");
// Store clean reply in history
const cleanReply = fullText.trim();
if (!cleanReply) throw new Error("No answer was received. Please try again.");
rbRenderChatText(bubble, cleanReply);
history.push({ role: "assistant", content: cleanReply.slice(0, 12000) });
if (history.length > MAX_HIST) history = history.slice(-MAX_HIST);
// Show routing CTA
if (route && TAB_META[route]) {
addRouteCTA(route, prefill);
}
} catch (err) {
controller.abort();
if (generation !== chatGeneration) return;
const message = cancelled
? rbWaitText("Stopped waiting. Your question is restored below; you can try again.", "تم إيقاف الانتظار. تمت استعادة سؤالك أدناه؛ يمكنك المحاولة مرة أخرى.")
: timedOut || err.name === "AbortError"
? rbWaitText("The chat request timed out. Your question is restored below. Please try again; the service may be starting up or busy.", "انتهت مهلة المحادثة. تمت استعادة سؤالك أدناه. يرجى المحاولة مرة أخرى؛ قد تكون الخدمة قيد التشغيل أو مشغولة.")
: rbWaitText(`Unable to complete the reply: ${err.message || "Please try again."}`, `تعذر إكمال الرد: ${err.message || "يرجى المحاولة مرة أخرى."}`);
rbRenderChatText(bubble, message);
history = history.filter((_, index) => index !== history.length - 1);
if (!input.value.trim()) input.value = text;
bubble.setAttribute("role", cancelled ? "status" : "alert");
} finally {
clearTimeout(timer);
waiting.remove();
if (generation === chatGeneration) { chatController = null; chatWait = null; chatTimer = null; isTyping = false; sendBtn.disabled = !input.value.trim(); }
}
}
// The introduction opens on request, so the form is ready without an overlay.
(function initServiceIntro() {
const backdrop = document.getElementById("rb-service-intro-backdrop");
const intro = document.getElementById("rb-service-intro");
const closeIntro = document.getElementById("rb-service-intro-close");
const exploreBtn = document.getElementById("rb-service-intro-explore");
const chatBtn = document.getElementById("rb-service-intro-chat");
const aboutBtn = document.getElementById("rb-service-intro-open");
if (!backdrop || !intro || !aboutBtn) return;
let armed = false;
let introReturnFocus = null;
const dismiss = () => {
backdrop.classList.remove("show");
backdrop.setAttribute("aria-hidden", "true");
backdrop.inert = true;
if (intro.contains(document.activeElement)) (introReturnFocus?.isConnected ? introReturnFocus : document.getElementById("s-subject"))?.focus({ preventScroll: true });
aboutBtn.setAttribute("aria-expanded", "false");
if (armed) {
document.removeEventListener("click", dismissOnFirstClick, false);
armed = false;
}
};
const dismissOnFirstClick = () => dismiss();
closeIntro?.addEventListener("click", dismiss);
exploreBtn?.addEventListener("click", () => {
dismiss();
RB_ROOT.querySelector(".tabs-bar")?.scrollIntoView({ behavior: "smooth", block: "start" });
});
chatBtn?.addEventListener("click", () => {
dismiss();
openPanel();
});
document.addEventListener("keydown", (event) => {
if (!backdrop.classList.contains("show")) return;
if (event.key === "Escape") { event.preventDefault(); dismiss(); }
if (event.key === "Tab") rbTrapFocus(intro, event);
});
aboutBtn.addEventListener("click", (event) => {
event.stopPropagation();
introReturnFocus = aboutBtn;
aboutBtn.setAttribute("aria-expanded", "true");
backdrop.inert = false;
backdrop.classList.add("show");
backdrop.setAttribute("aria-hidden", "false");
window.ResearchBee.serviceIntroShownThisLoad = true;
intro.focus({ preventScroll: true });
armed = true;
document.addEventListener("click", dismissOnFirstClick, false);
});
})();
// Tooltip on first load. Do not stack it on top of the service intro.
chatHintTimer = setTimeout(() => {
badge.classList.add("visible");
if (!window.ResearchBee.serviceIntroShownThisLoad) {
tooltip.classList.add("show");
chatHintHideTimer = setTimeout(() => tooltip.classList.remove("show"), 4000);
}
}, 2500);
})();
window.ResearchBee.frontendVersion = "1.9.3-links";
/* ========================================================================
ResearchBee v1.8 — unified verified journal discovery UI
The same renderer, policy checks, comparison and export are used by both
subject browsing and manuscript matching.
======================================================================== */
const RB_DISCOVERY_STATE = {
generation: 0,
mode: "",
result: null,
all: [],
byKey: new Map(),
selected: new Set(),
container: null,
context: { funder: "", intended_repository: "Institutional repository" },
};
function rbV18Value(id) {
return document.getElementById(id)?.value?.trim() || "";
}
function rbV18JournalKey(journal) {
return String(journal?.id || journal?.scopus_id || journal?.issn || journal?.name || "");
}
function rbV18AllJournals(result) {
return [...(result?.journals || []), ...(result?.extended_list || [])];
}
function rbV18Quartile(journal) {
return journal?.quartile || journal?.ranking?.quartile || "";
}
function rbV18HIndex(journal) {
return Number(journal?.h_index ?? journal?.ranking?.h_index ?? 0) || 0;
}
function rbV18MatchedSubject(journal) {
const rows = Array.isArray(journal?.matched_subjects) ? journal.matched_subjects : [];
const withField = rows.filter(row => row && row.field);
if (!withField.length) return rbV18Quartile(journal) || "Not resolved";
return withField.slice(0, 2).map(row => `${row.field}${row.quartile ? ` (${row.quartile})` : ""}`).join("; ");
}
function rbV18GetManuscriptData() {
return {
title: rbV18Value("j-title"),
abstract: rbV18Value("j-abstract"),
keywords: rbV18Value("j-keywords"),
discipline: rbV18Value("j-discipline"),
article_type: rbV18Value("j-article-type") || "Original research article",
methods: rbV18Value("j-methods"),
audience: rbV18Value("j-audience"),
funder: rbV18Value("j-funder"),
institution: rbV18Value("j-institution"),
country: rbV18Value("j-country"),
apc_budget: rbV18Value("j-apc"),
access_preference: rbV18Value("j-access-pref") || "Any journal",
sharing_requirement: Boolean(document.getElementById("j-sharing-required")?.checked),
intended_repository: rbV18Value("j-repo-target") || "Institutional repository",
ranking_preference: rbV18Value("j-ranking-pref") || "No filter",
preferred_journals: rbV18Value("j-preferred"),
avoid_journals: rbV18Value("j-avoid"),
// Empty legacy fields keep the request compatible without reintroducing
// Green OA as a journal business-model filter.
oa_preference: "",
ranking_source: "",
speed_preference: "",
repository_target: "",
};
}
function rbV18GetSubjectData() {
return {
subject: rbV18Value("s-subject"),
ranking_preference: rbV18Value("s-ranking-pref") || "No filter",
access_preference: rbV18Value("s-access-pref") || "Any journal",
sharing_requirement: Boolean(document.getElementById("s-sharing-required")?.checked),
intended_repository: rbV18Value("s-repo-target") || "Institutional repository",
apc_budget: rbV18Value("s-apc"),
funder: rbV18Value("s-funder"),
preferred_journals: rbV18Value("s-preferred"),
avoid_journals: rbV18Value("s-avoid"),
model: getModel(),
language: getLanguage(),
};
}
function rbV18InitialiseState(result, container, mode, context) {
RB_DISCOVERY_STATE.generation += 1;
RB_DISCOVERY_STATE.mode = mode;
RB_DISCOVERY_STATE.result = result;
RB_DISCOVERY_STATE.all = rbV18AllJournals(result);
RB_DISCOVERY_STATE.byKey = new Map();
RB_DISCOVERY_STATE.selected = new Set();
RB_DISCOVERY_STATE.container = container;
RB_DISCOVERY_STATE.context = context || { funder: "", intended_repository: "Institutional repository" };
RB_DISCOVERY_STATE.all.forEach(journal => {
const key = rbV18JournalKey(journal);
if (key) RB_DISCOVERY_STATE.byKey.set(key, journal);
});
RB_COVER_LETTER_PAYLOADS.clear();
RB_RELATED_WORK_PAYLOADS.clear();
}
function rbV18List(items, emptyText) {
const values = (items || []).filter(Boolean);
return values.length
? `<ul class="rb-criteria-list">${values.map(item => `<li>${esc(item)}</li>`).join("")}</ul>`
: `<p style="font-size:12px;color:var(--text-muted)">${esc(emptyText)}</p>`;
}
function rbV18RenderCriteria(result) {
return `
<section class="rb-criteria-card" aria-label="Applied and unverified selection criteria">
<div class="rb-criteria-columns">
<div class="rb-verified-box">
<h4>✓ Applied before ranking</h4>
${rbV18List(result.applied_criteria, "No additional hard filters were selected.")}
</div>
<div class="rb-unverified-box">
<h4>Needs a current or manual check</h4>
${rbV18List(result.unverified_criteria, "No unresolved criteria were reported.")}
</div>
</div>
<p style="font-size:11.5px;color:var(--text-muted)">ResearchBee does not silently relax a selected hard filter. Missing policy, fee, or timing data remains unknown.</p>
</section>`;
}
function rbV18RenderUnderstanding(result, mode) {
if (mode === "manuscript") {
const understanding = result.manuscript_understanding || {};
const keywords = Array.isArray(understanding.keywords) ? understanding.keywords : [];
return `
${renderManuscriptUnderstanding(understanding)}
<div class="rb-refine-row">
<button class="rb-refine-btn" id="rb-refine-manuscript" type="button">Review or correct inferred details</button>
${keywords.length ? `<span style="font-size:11.5px;color:var(--text-muted);align-self:center">Inferred keywords: ${keywords.map(esc).join(", ")}</span>` : ""}
</div>`;
}
const subject = result.subject_understanding || {};
const mapping = result.subject_mapping || {};
const alternatives = Array.isArray(mapping.alternatives) ? mapping.alternatives : [];
const mappingClass = mapping.spelling_corrected ? " spelling"
: (mapping.used_nearest_category || mapping.match_type === "synonym") ? " nearest" : "";
const mappingMessage = result.user_message || "Subject relevance is based on the verified ASJC/SCImago mapping.";
return `
<section class="card understanding">
<div class="card-header"><h2>🧭 Subject interpretation</h2></div>
<div class="card-body">
<p style="font-size:14px">${esc(subject.summary || "Verified subject discovery")}</p>
<div class="tag-row">
${subject.category ? `<span class="badge b-primary">${esc(subject.category)}</span>` : ""}
${subject.area ? `<span class="badge b-muted">${esc(subject.area)}</span>` : ""}
${subject.confidence ? `<span class="badge b-muted">${esc(subject.confidence)} match</span>` : ""}
</div>
<div class="rb-subject-map-note${mappingClass}">${esc(mappingMessage)}</div>
${alternatives.length ? `<div class="rb-subject-alternatives">
<span class="rb-subject-alternatives-label">Try another verified category:</span>
${alternatives.map(item => `<button type="button" class="rb-refine-btn rb-subject-suggestion" data-subject="${esc(item.category || item)}">${esc(item.category || item)}${item.n_journals ? ` (${item.n_journals})` : ""}</button>`).join("")}
</div>` : ""}
</div>
</section>`;
}
function rbV18IdentityBadge(journal) {
const identity = journal.identity_verification || {};
const label = identity.status === "Confirmed" ? "Journal identity verified" : "Confirm journal identity";
return `<span class="rb-id-badge" title="${esc(identity.method || "Verified journal index")}">✓ ${esc(label)}</span>`;
}
function rbV18AccessBadge(journal) {
const access = journal.access_model || {};
const evidence = access.verification || "Journal-level source flag; verify current terms on the journal website.";
if (access.code === "diamond") return `<span class="badge b-diamond" title="${esc(evidence)}">◆ Diamond OA · source flag</span>`;
if (access.code === "open") return `<span class="badge b-success" title="${esc(evidence)}">✓ Open-access journal · source flag</span>`;
return `<span class="badge b-muted" title="${esc(evidence)}">OA status not confirmed</span>`;
}
function rbV18PolicyBadge(journal) {
const policy = journal.sharing_policy || {};
if (policy.status !== "confirmed") return "";
const state = policy.requirement_status;
if (state === "meets") return `<span class="badge b-success">AAM sharing option found</span>`;
if (state === "conditional") return `<span class="badge b-warning">AAM sharing conditional</span>`;
if (state === "does_not_meet") return `<span class="badge b-danger">AAM sharing not permitted</span>`;
return `<span class="badge b-warning">Policy retrieved · applicability check</span>`;
}
function rbV18RenderFitBreakdown(journal) {
const components = Array.isArray(journal.fit_components) ? journal.fit_components : [];
if (!components.length) return "";
return `
<div class="rb-fit-breakdown">
<h5>Why this fit score was assigned</h5>
${journal.scoring_note ? `<p class="rb-scoring-note">${esc(journal.scoring_note)}</p>` : ""}
${components.map(component => {
const score = Number(component.score || 0);
const max = Math.max(Number(component.max || 0), 1);
const width = Math.max(0, Math.min(100, Math.round(score / max * 100)));
return `<div class="rb-fit-component">
<span class="rb-fit-component-label">${esc(component.label || component.key)}</span>
<span class="rb-fit-bar" aria-hidden="true"><span style="width:${width}%"></span></span>
<span class="rb-fit-component-value">${score}/${max}</span>
</div>`;
}).join("")}
<p style="font-size:11px;color:var(--text-muted);margin-top:7px">Scope and subject fit carry more weight than journal rank. The score supports comparison; it does not predict acceptance.</p>
</div>`;
}
function rbV18ArticleUrl(item) {
return safeHttpsUrl(item?.doi || item?.openalex_url || "");
}
function rbV18RenderEvidence(journal) {
const works = Array.isArray(journal.similar_articles) ? journal.similar_articles : [];
const note = journal.article_evidence_summary || (
works.length ? "Recent article-title evidence supports this match." : "Recent article evidence was unavailable."
);
return `
<div class="rb-evidence">
<h5>📄 Recent article evidence</h5>
<p class="rb-evidence-note">${esc(note)}${journal.article_similarity_score ? ` Local title-overlap signal: ${esc(String(journal.article_similarity_score))}/100.` : ""}</p>
${works.length ? `<ol class="rb-evidence-list">${works.slice(0, 3).map(item => {
const url = rbV18ArticleUrl(item);
const title = esc(item.title || "Untitled work");
const meta = [item.year, item.cited_by != null ? `${item.cited_by} citations` : ""].filter(Boolean).join(" · ");
return `<li>${url ? `<a href="${esc(url)}" target="_blank" rel="noopener noreferrer">${title}</a>` : title}${meta ? ` <span style="color:var(--text-muted)">(${esc(meta)})</span>` : ""}</li>`;
}).join("")}</ol>` : `<p style="font-size:12px;color:var(--text-muted)">No recent OpenAlex article titles were available. Review the journal’s current aims, scope and recent issues manually.</p>`}
</div>`;
}
function rbV18RenderAccessPanel(journal) {
const access = journal.access_model || {};
return `
<div class="rb-info-panel rb-access-panel">
<h5>🔓 Journal access model</h5>
<p><strong>${esc(access.label || "Not confirmed")}</strong></p>
<p>${esc(access.author_fee_status || "Current title-level APC is not available in the journal index.")}</p>
<p style="margin-top:5px;font-size:11px">${esc(access.verification || "Verify current access and fee terms on the journal website.")}</p>
</div>`;
}
function rbV18RenderKuPanel(journal) {
const publisherSignal = Boolean(journal.ku_agreement_publisher);
const candidate = Boolean(journal.ku_apc_candidate);
const heading = candidate
? "Potential KU publisher-agreement candidate"
: publisherSignal
? "KU publisher-level agreement signal"
: "No configured KU agreement signal";
const publisherLink = publisherSignal ? safeHttpsUrl(getKuPubPage(journal.publisher)) : "";
return `
<div class="rb-info-panel rb-ku-panel">
<h5>🎓 KU APC planning</h5>
<p><strong>${esc(heading)}</strong></p>
<p>${esc(journal.ku_apc_status || "Eligibility is not confirmed by Journal Finder.")}</p>
${publisherSignal ? `<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:7px">
${publisherLink ? `<a href="${esc(publisherLink)}" target="_blank" rel="noopener noreferrer" class="vlink">Publisher process</a>` : ""}
<a href="${esc(KU_RATINGS)}" target="_blank" rel="noopener noreferrer" class="vlink">Check exact rating eligibility</a>
</div>` : ""}
</div>`;
}
function rbV18AamSummary(journal) {
const policy = journal.sharing_policy || {};
if (policy.status !== "confirmed") return policy.status === "unavailable" ? "Policy unavailable" : "Not checked";
const postprint = policy.green_oa?.postprint || {};
const parts = [postprint.allowed || "Unclear", postprint.embargo, postprint.where].filter(Boolean);
return parts.join(" · ") || "Retrieved; review options";
}
function rbV18PolicyRequirementLabel(state) {
return {
meets: "Accepted-manuscript requirement appears met",
conditional: "Accepted-manuscript sharing is conditional",
does_not_meet: "Retrieved options do not meet the requirement",
unknown: "Applicability remains unknown",
not_requested: "No sharing requirement selected",
}[state] || "Applicability remains unknown";
}
function rbV18RenderPolicyPanel(journal) {
const key = rbV18JournalKey(journal);
const policy = journal.sharing_policy || { status: "not_checked" };
const verifyUrl = safeHttpsUrl(policy.verify_url || journal.verify_links?.sherpa_romeo || "");
let resultHtml = "";
if (policy.status === "loading") {
resultHtml = `<div class="rb-policy-unknown">Checking Jisc Open Policy Finder…</div>`;
} else if (policy.status === "confirmed" && policy.green_oa) {
const green = policy.green_oa;
resultHtml = `
<div class="rb-policy-result">
${provenanceBadge(green, "journal_api")}
${rbRenderPolicyEvaluation(policy.policy_evaluation || green.policy_evaluation)}
<p class="rb-policy-status" style="margin-top:8px"><strong>${esc(rbV18PolicyRequirementLabel(policy.requirement_status))}.</strong> Select the policy option that applies to the manuscript, funder and deposit location.</p>
<div class="version-list">
${renderVersionBlock("Submitted version / preprint", green.preprint)}
${renderVersionBlock("Accepted manuscript (AAM / postprint)", green.postprint)}
${renderVersionBlock("Published version (Version of Record)", green.published_version)}
</div>
${renderSourcePanel(green, {})}
<p style="font-size:11.5px;color:var(--text-muted);margin-top:9px">This is a journal-level policy. After publication, use the article DOI in License Checking for an article-level permission and Khazna status check.</p>
</div>`;
} else if (policy.status === "unavailable") {
resultHtml = `<div class="rb-policy-result rb-policy-unknown"><strong>Policy not retrieved.</strong> ${esc(policy.message || "No matching journal-level record was available.")}</div>`;
} else {
resultHtml = `<p class="rb-policy-status">Sharing policy not yet checked. Retrieve the journal-level version, embargo, licence and location options before planning deposit.</p>`;
}
return `
<div class="rb-info-panel rb-policy-panel">
<h5>🛡 Sharing policy</h5>
${resultHtml}
<div class="rb-policy-actions" style="margin-top:8px">
<button type="button" class="rb-policy-check-btn" data-policy-key="${esc(key)}" ${policy.status === "loading" ? "disabled aria-busy=\"true\"" : ""}>${policy.status === "confirmed" ? "Refresh policy" : "Check sharing policy"}</button>
${verifyUrl ? `<a href="${esc(verifyUrl)}" target="_blank" rel="noopener noreferrer" class="vlink">Open public record search</a>` : ""}
</div>
</div>`;
}
function rbV18RenderVerification(journal) {
const links = journal.verify_links || {};
return renderVerifyLinks({
scopus: links.scopus || links.scopus_sources,
sherpa_romeo: links.sherpa_romeo,
doaj: links.doaj,
openalex: links.openalex,
});
}
function rbV18RenderDetailedCard(journal, index, mode) {
const key = rbV18JournalKey(journal);
const uid = rbDomKey(key, `journal-${index}`);
const quartile = rbV18Quartile(journal);
const qRank = ({ Q1: 1, Q2: 2, Q3: 3, Q4: 4 })[quartile] || 9;
const accessRank = journal.access_model?.code === "diamond" ? 0 : journal.access_model?.code === "open" ? 1 : 2;
const actions = mode === "manuscript"
? `${renderCoverLetterBtn(journal, window.ResearchBee.lastManuscript || {}, uid)}`
: `<button type="button" class="rb-refine-btn rb-analyse-from-subject" data-journal-key="${esc(key)}">Analyse this journal with a manuscript</button>`;
const ranking = journal.ranking;
const rankingNote = ranking ? [ranking.source, ranking.year, ranking.verification_status || "Unverified — check manually"].filter(Boolean).join(" · ") : "";
return `
<article class="card j-card rb-discovery-card" data-key="${esc(key)}"
data-fit="${Number(journal.fit_score || 0)}" data-quartile="${qRank}"
data-hindex="${rbV18HIndex(journal)}" data-access="${accessRank}">
<div class="rb-fit-score" title="Explainable comparison score, not an acceptance prediction"><strong>${esc(String(journal.fit_score ?? "–"))}</strong><span>fit / 100</span></div>
<div class="j-header">
<div class="j-meta"><span class="rb-rank-number">#${index + 1}</span> · ${esc(journal.publisher || "Publisher not listed")}${journal.issn ? ` · ISSN ${esc(journal.issn)}` : ""}</div>
<div class="j-title">${rbJournalTitle(journal)}</div>${rbJournalLinks(journal)}
<div class="rb-identity-row">
${rbV18IdentityBadge(journal)}
${quartile ? quartileBadge(quartile) : ""}
${rbV18AccessBadge(journal)}
${rbV18PolicyBadge(journal)}
</div>
<label class="rb-card-select"><input class="rb-compare-checkbox" type="checkbox" data-compare-key="${esc(key)}"/> Add to comparison</label>
</div>
<div class="j-body">
${renderIndexationNotice(journal)}
<div class="rb-card-fit"><h5>🎯 Why it fits</h5><p>${esc(journal.fit_reason || "Verified subject and journal metadata support this match.")}</p></div>
${rankingNote ? `<p class="rb-card-ranking-note"><strong>Ranking source and verification:</strong> ${esc(rankingNote)}</p>` : ""}
<div class="rb-refine-row rb-card-primary-actions">${actions}</div>
<details class="rb-journal-details">
<summary><span class="rb-details-closed-label">View journal details</span><span class="rb-details-open-label">Hide journal details</span></summary>
<div class="rb-journal-details-body">
<div class="detail-grid">
<div class="detail-item"><h5>👥 Audience match</h5><p>${esc(journal.audience_match || "Review the journal's current audience and recent issues.")}</p></div>
<div class="detail-item"><h5>📋 Submission strategy</h5><p>${esc(journal.submission_strategy || "Review current author instructions before submission.")}</p></div>
<div class="detail-item"><h5>🔓 Open Access planning</h5><p>${esc(journal.open_access_planning || "Check current access, fees and sharing rights separately.")}</p></div>
</div>
${rbV18RenderFitBreakdown(journal)}
${renderRankingBlock(journal.ranking, journal)}
<div class="rb-section-grid">
${rbV18RenderAccessPanel(journal)}
${rbV18RenderKuPanel(journal)}
</div>
<div id="rb-policy-panel-${uid}" class="rb-policy-panel-host" data-policy-host-key="${esc(key)}">${rbV18RenderPolicyPanel(journal)}</div>
${rbV18RenderEvidence(journal)}
${renderOpenAlexMetrics(journal.openalex)}
${renderRelatedWorksAccordion(journal, uid)}
${rbV18RenderVerification(journal)}
${renderDeeperAnalysisStrip(journal.name, journal.issn)}
</div>
</details>
</div>
</article>`;
}
function rbV18RenderExtraTable(journals) {
if (!journals.length) return "";
return `
<div class="extended-wrap">
<button type="button" class="ext-toggle" id="rb-extra-toggle"><span>📋 Show ${journals.length} additional verified possibilities</span><span class="ext-arrow">▼</span></button>
<div class="ext-body" id="rb-extra-body">
<table class="ext-table rb-extra-table">
<thead><tr><th>#</th><th>Journal</th><th>Fit</th><th>Matched field</th><th>Access</th><th>Shortlist &amp; policy</th></tr></thead>
<tbody>${journals.map((journal, index) => {
const key = rbV18JournalKey(journal);
const q = rbV18Quartile(journal);
return `<tr data-key="${esc(key)}">
<td>${index + 6}</td>
<td><strong>${rbJournalTitle(journal)}</strong>${rbJournalLinks(journal)}${rbCategoryRows(journal)}<br><span style="font-size:11px;color:var(--text-muted)">${esc(journal.publisher || "")}${journal.issn ? ` · ${esc(journal.issn)}` : ""}</span></td>
<td><span class="rb-extra-score">${esc(String(journal.fit_score ?? "–"))}/100</span></td>
<td>${q ? quartileBadge(q) : ""}<span style="display:block;margin-top:4px;font-size:11px;color:var(--text-muted)">${esc(rbV18MatchedSubject(journal))}</span></td>
<td>${rbV18AccessBadge(journal)}</td>
<td><div class="rb-extra-actions">
<label style="display:inline-flex;align-items:center;gap:4px;font-size:10.5px"><input class="rb-compare-checkbox" type="checkbox" data-compare-key="${esc(key)}"/> Compare</label>
<button type="button" class="rb-extra-policy" data-policy-key="${esc(key)}">Check policy</button>
${RB_DISCOVERY_STATE.mode === "subject" ? `<button type="button" class="rb-extra-policy rb-analyse-from-subject" data-journal-key="${esc(key)}">Analyse manuscript</button>` : ""}
</div></td>
</tr><tr class="rb-extra-policy-row"><td colspan="6"><details><summary>${esc(journal.name)} — Sharing policy details</summary><div class="rb-policy-panel-host" data-policy-host-key="${esc(key)}">${rbV18RenderPolicyPanel(journal)}</div></details></td></tr>`;
}).join("")}</tbody>
</table>
</div>
</div>`;
}
function rbV18ComparisonRows(journals) {
const rows = [
["Fit score", j => `${j.fit_score ?? "–"}/100`],
["Relevant subject / quartile", j => rbV18MatchedSubject(j)],
["Current index status", j => j.currently_indexed === false ? "Not currently indexed" : "Active Scopus source record"],
["Access model", j => j.access_model?.label || "Not confirmed"],
["Current APC", j => j.access_model?.author_fee_status || "Unknown"],
["KU agreement signal", j => j.ku_apc_status || "Not confirmed"],
["Accepted manuscript policy", j => rbV18AamSummary(j)],
["Recent article evidence", j => `${(j.similar_articles || []).length} representative article(s)${j.article_similarity_score ? ` · overlap ${j.article_similarity_score}/100` : ""}`],
["Key caution", j => j.warn ? (j.state_message || "Indexation warning") : (j.sharing_policy?.status === "confirmed" ? "Review policy applicability and current journal instructions" : "Sharing policy and current fee still need checking")],
];
return rows.map(([label, getter]) => `
<tr><td>${esc(label)}</td>${journals.map(journal => `<td>${esc(getter(journal))}</td>`).join("")}</tr>`).join("");
}
function rbV18RenderComparison() {
const panel = document.getElementById("rb-comparison-panel");
if (!panel) return;
const journals = RB_DISCOVERY_STATE.all.filter(journal => RB_DISCOVERY_STATE.selected.has(rbV18JournalKey(journal)));
if (!journals.length) {
panel.innerHTML = `<div class="rb-comparison-empty">Select two to five journals to build a side-by-side decision table. You may select one journal first and add others later.</div>`;
return;
}
panel.innerHTML = `
<div class="rb-comparison-head">
<div><h3>Journal decision table</h3><span class="rb-shortlist-count">${journals.length} of 5 selected</span></div>
<div style="display:flex;gap:7px;flex-wrap:wrap">
<button type="button" class="rb-export-compare" id="rb-export-comparison">Export CSV</button>
<button type="button" class="rb-export-compare" id="rb-clear-comparison">Clear shortlist</button>
</div>
</div>
<div class="rb-comparison-scroll"><table class="rb-comparison-table">
<thead><tr><th>Criterion</th>${journals.map(journal => `<th>${rbJournalTitle(journal)}</th>`).join("")}</tr></thead>
<tbody><tr><td>${esc(rbText("Journal links"))}</td>${journals.map(j => `<td>${rbJournalLinks(j)}</td>`).join("")}</tr><tr><td>SCImago SJR</td>${journals.map(j => `<td>${rbCategoryRows(j)}</td>`).join("")}</tr>${rbV18ComparisonRows(journals)}</tbody>
</table></div>`;
document.getElementById("rb-export-comparison")?.addEventListener("click", rbV18ExportComparison);
document.getElementById("rb-clear-comparison")?.addEventListener("click", () => {
RB_DISCOVERY_STATE.selected.clear();
RB_DISCOVERY_STATE.container?.querySelectorAll(".rb-compare-checkbox").forEach(box => { box.checked = false; });
rbV18RenderComparison();
rbV18UpdateShortlistCount();
});
rbApplyUiLanguage(panel);
}
function rbV18Csv(value) {
let text = String(value ?? "");
if (/^[\s]*[=+@-]/.test(text) || /^[\t\r\n]/.test(text)) text = "'" + text;
return `"${text.replace(/"/g, '\"\"')}"`;
}
function rbV18ExportComparison() {
const journals = RB_DISCOVERY_STATE.all.filter(journal => RB_DISCOVERY_STATE.selected.has(rbV18JournalKey(journal)));
if (!journals.length) return;
const headers = ["Journal", "Publisher", "ISSN", "Fit score", "Matched subject", "Quartile", "H-index", "Access model", "APC status", "KU agreement signal", "Accepted manuscript policy", "Recent evidence", "Scopus ID"];
const rows = journals.map(journal => [
journal.name, journal.publisher, journal.issn, journal.fit_score,
rbV18MatchedSubject(journal), rbV18Quartile(journal), rbV18HIndex(journal),
journal.access_model?.label, journal.access_model?.author_fee_status,
journal.ku_apc_status, rbV18AamSummary(journal),
`${(journal.similar_articles || []).length} article(s); overlap ${journal.article_similarity_score || 0}/100`,
journal.scopus_id || journal.id,
]);
const csv = [headers, ...rows].map(row => row.map(rbV18Csv).join(",")).join("\r\n");
const blob = new Blob(["\ufeff" + csv], { type: "text/csv;charset=utf-8" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = "researchbee-journal-comparison.csv";
document.body.appendChild(link);
link.click();
link.remove();
URL.revokeObjectURL(url);
}
function rbV18UpdateShortlistCount(message = "") {
const count = document.getElementById("rb-shortlist-count");
if (count) count.textContent = message || (getLanguage() === "arabic" ? `تم اختيار ${RB_DISCOVERY_STATE.selected.size} من 5` : `${RB_DISCOVERY_STATE.selected.size} of 5 selected`);
}
function rbV18SetCompare(key, checked, checkbox) {
if (!key) return;
if (checked && RB_DISCOVERY_STATE.selected.size >= 5 && !RB_DISCOVERY_STATE.selected.has(key)) {
if (checkbox) checkbox.checked = false;
rbV18UpdateShortlistCount("Maximum 5 journals. Remove one before adding another.");
return;
}
if (checked) RB_DISCOVERY_STATE.selected.add(key);
else RB_DISCOVERY_STATE.selected.delete(key);
RB_DISCOVERY_STATE.container?.querySelectorAll(".rb-compare-checkbox").forEach(box => {
if (box.dataset.compareKey === key) box.checked = RB_DISCOVERY_STATE.selected.has(key);
});
rbV18UpdateShortlistCount();
rbV18RenderComparison();
}
function rbV18RefreshPolicyPanel(key) {
const journal = RB_DISCOVERY_STATE.byKey.get(key);
if (!journal) return;
RB_DISCOVERY_STATE.container?.querySelectorAll(".rb-policy-panel-host").forEach(host => {
if (host.dataset.policyHostKey === key) {
host.innerHTML = rbV18RenderPolicyPanel(journal);
const details = host.closest("details");
if (details && journal.sharing_policy?.status === "loading") details.open = true;
}
});
RB_DISCOVERY_STATE.container?.querySelectorAll("[data-policy-key]").forEach(button => {
if (button.dataset.policyKey !== key || button.closest(".rb-policy-panel-host")) return;
const status = journal.sharing_policy?.status;
button.textContent = status === "confirmed" ? "Policy checked" : status === "loading" ? "Checking…" : "Check policy";
button.disabled = status === "loading";
});
rbV18WirePolicyButtons(RB_DISCOVERY_STATE.container);
rbV18RenderComparison();
}
async function rbV18CheckPolicies(keys, trigger) {
const unique = [...new Set((keys || []).filter(key => RB_DISCOVERY_STATE.byKey.has(key) && RB_DISCOVERY_STATE.byKey.get(key).sharing_policy?.status !== "loading"))].slice(0, 5);
if (!unique.length) return;
const generation = RB_DISCOVERY_STATE.generation;
const journalsByKey = new Map(unique.map(key => [key, RB_DISCOVERY_STATE.byKey.get(key)]));
const context = { ...RB_DISCOVERY_STATE.context };
const original = trigger?.textContent || "";
if (trigger) { trigger.disabled = true; trigger.textContent = "Checking…"; }
unique.forEach(key => {
const journal = journalsByKey.get(key);
journal.sharing_policy = { ...(journal.sharing_policy || {}), status: "loading", message: "Checking Jisc Open Policy Finder…" };
rbV18RefreshPolicyPanel(key);
});
try {
const response = await callAPI("/api/check-journal-policies", {
journals: unique.map(key => {
const journal = journalsByKey.get(key);
return { key, name: journal.name, issn: journal.issn || "", publisher: journal.publisher || "" };
}),
manuscript_version: "Accepted manuscript (AAM / postprint)",
intended_repository: context.intended_repository || "Institutional repository",
funder: context.funder || "",
language: getLanguage(),
});
if (generation !== RB_DISCOVERY_STATE.generation) return;
(response.results || []).forEach(item => {
const journal = RB_DISCOVERY_STATE.byKey.get(String(item.key || ""));
if (journal) journal.sharing_policy = item.policy || { status: "unavailable", requirement_status: "unknown", message: "Policy not retrieved." };
});
unique.forEach(key => {
const journal = journalsByKey.get(key);
if (journal.sharing_policy?.status === "loading") journal.sharing_policy = { status: "unavailable", requirement_status: "unknown", message: "The service did not return a policy result for this journal. Please try again." };
});
} catch (error) {
if (generation !== RB_DISCOVERY_STATE.generation) return;
unique.forEach(key => {
const journal = journalsByKey.get(key);
journal.sharing_policy = { status: "unavailable", requirement_status: "unknown", message: error.message || "Policy lookup failed." };
});
} finally {
if (generation === RB_DISCOVERY_STATE.generation) { unique.forEach(rbV18RefreshPolicyPanel); rbApplyUiLanguage(RB_DISCOVERY_STATE.container); }
if (trigger) { trigger.disabled = false; trigger.textContent = original || "Check policies for top 3"; }
}
}
function rbV18WirePolicyButtons(root) {
root?.querySelectorAll("[data-policy-key]").forEach(button => {
if (button.dataset.rbPolicyWired === "1") return;
button.dataset.rbPolicyWired = "1";
button.addEventListener("click", () => rbV18CheckPolicies([button.dataset.policyKey || ""], button));
});
}
function rbV18PrefillManuscriptFromResult() {
const understanding = RB_DISCOVERY_STATE.result?.manuscript_understanding || {};
const fillIfBlank = (id, value) => {
const element = document.getElementById(id);
if (element && !element.value.trim() && value) element.value = Array.isArray(value) ? value.join(", ") : value;
};
fillIfBlank("j-keywords", understanding.keywords);
fillIfBlank("j-discipline", understanding.discipline);
fillIfBlank("j-methods", understanding.methods);
fillIfBlank("j-audience", understanding.audience);
const details = document.getElementById("manuscript-advanced");
if (details) details.open = true;
switchMode("manuscript");
document.getElementById("journal-form")?.scrollIntoView({ behavior: "smooth", block: "start" });
}
function rbV18AnalyseFromSubject(key) {
const journal = RB_DISCOVERY_STATE.byKey.get(key);
if (!journal) return;
switchMode("manuscript");
const preferred = document.getElementById("j-preferred");
if (preferred) {
const current = preferred.value.split(/[;\n]+/).map(value => value.trim()).filter(Boolean);
if (!current.some(value => value.toLowerCase() === String(journal.name).toLowerCase())) current.unshift(journal.name);
preferred.value = current.join("\n");
}
const details = document.getElementById("manuscript-advanced");
if (details) details.open = true;
document.getElementById("journal-form")?.scrollIntoView({ behavior: "smooth", block: "start" });
}
function rbV18WireDiscovery(root) {
root?.querySelectorAll(".rb-edit-search").forEach(button => button.addEventListener("click", () => rbV18EditSearch(button.dataset.editMode || "subject")));
root?.querySelectorAll(".rb-compare-checkbox").forEach(box => {
box.checked = RB_DISCOVERY_STATE.selected.has(box.dataset.compareKey || "");
box.addEventListener("change", () => rbV18SetCompare(box.dataset.compareKey || "", box.checked, box));
});
rbV18WirePolicyButtons(root);
document.getElementById("rb-bulk-policy")?.addEventListener("click", event => {
const keys = RB_DISCOVERY_STATE.all.slice(0, 3).map(rbV18JournalKey);
rbV18CheckPolicies(keys, event.currentTarget);
});
document.getElementById("rb-compare-open")?.addEventListener("click", () => {
document.getElementById("rb-comparison-panel")?.scrollIntoView({ behavior: "smooth", block: "start" });
});
document.getElementById("rb-extra-toggle")?.addEventListener("click", event => {
event.currentTarget.classList.toggle("open");
document.getElementById("rb-extra-body")?.classList.toggle("show");
});
document.getElementById("rb-refine-manuscript")?.addEventListener("click", rbV18PrefillManuscriptFromResult);
root?.querySelectorAll(".rb-analyse-from-subject").forEach(button => {
button.addEventListener("click", () => rbV18AnalyseFromSubject(button.dataset.journalKey || ""));
});
document.getElementById("journal-reset")?.addEventListener("click", () => rbV18Reset("manuscript"));
document.getElementById("subject-reset")?.addEventListener("click", () => rbV18Reset("subject"));
root?.querySelectorAll(".rb-subject-suggestion").forEach(button => {
button.addEventListener("click", () => {
const input = document.getElementById("s-subject");
if (input) input.value = button.dataset.subject || "";
document.getElementById("subject-form")?.requestSubmit();
});
});
wireCoverLetterButtons(root);
wireRelatedWorks(root);
rbV18RenderComparison();
}
function rbV18EditSearch(mode) {
switchMode(mode);
const form = document.getElementById(mode === "subject" ? "subject-form" : "journal-form");
form?.scrollIntoView({ behavior: "smooth", block: "start" });
form?.querySelector("input, textarea")?.focus({ preventScroll: true });
}
function rbV18Reset(mode) {
rbCancelRequest("discovery");
RB_DISCOVERY_STATE.generation += 1;
const container = document.getElementById(mode === "subject" ? "subject-results" : "journal-results");
const progress = document.getElementById(mode === "subject" ? "subject-progress" : "journal-progress");
const form = document.getElementById(mode === "subject" ? "subject-form" : "journal-form");
if (container) { container.innerHTML = ""; container.classList.add("hidden"); }
progress?.classList.remove("show");
form?.reset();
RB_DISCOVERY_STATE.selected.clear();
form?.scrollIntoView({ behavior: "smooth", block: "start" });
}
function rbV18RenderNoResults(result, container, mode) {
const suggestions = Array.isArray(result.suggestions) ? result.suggestions : [];
const title = result.filter_no_match ? "No journal met every selected hard filter" : "No verified journal match found";
const message = result.global_notes || result.user_message || "Try a recognised subject or revise the selected filters.";
container.innerHTML = `
<div class="rb-no-results">
<h3>${esc(title)}</h3>
<p>${esc(message)}</p>
${suggestions.length ? `<div class="rb-refine-row" style="justify-content:center;margin-top:13px">${suggestions.map(item => `<button type="button" class="rb-refine-btn rb-subject-suggestion" data-subject="${esc(item.category || item)}">${esc(item.category || item)}${item.n_journals ? ` (${item.n_journals})` : ""}</button>`).join("")}</div>` : ""}
<div class="rb-refine-row" style="justify-content:center;margin-top:13px"><button type="button" class="rb-refine-btn rb-edit-search" data-edit-mode="${mode}">Edit search</button></div>
</div>`;
rbV18WireDiscovery(container);
rbApplyUiLanguage(container);
}
function rbV18RenderDiscoveryResults(result, container, mode) {
const all = rbV18AllJournals(result);
const context = mode === "manuscript"
? { funder: rbV18Value("j-funder"), intended_repository: rbV18Value("j-repo-target") || "Institutional repository" }
: { funder: rbV18Value("s-funder"), intended_repository: rbV18Value("s-repo-target") || "Institutional repository" };
rbV18InitialiseState(result, container, mode, context);
if (!all.length) {
rbV18RenderNoResults(result, container, mode);
return;
}
const intro = mode === "manuscript"
? "Here are the strongest verified journal matches for your manuscript. Scope fit is weighted more heavily than rank."
: "Here are active, verified journals in the interpreted subject. Use the evidence and comparison table to refine the shortlist.";
container.innerHTML = `
${renderMascotRow(intro)}
<div class="results-header">
<h2 class="results-title">${mode === "manuscript" ? "Manuscript journal analysis" : "Subject journal discovery"}</h2>
<div class="results-meta"><span class="count-chip">${all.length} verified journal${all.length === 1 ? "" : "s"}</span><button class="btn btn-ghost" id="${mode === "subject" ? "subject-reset" : "journal-reset"}" type="button">↩ Start over</button></div>
</div>
${rbV18RenderUnderstanding(result, mode)}
${rbV18RenderCriteria(result)}
${result.scoring_note ? `<div class="policy-notes rb-scoring-note" role="note">${esc(result.scoring_note)}</div>` : ""}
<div class="rb-journal-toolbar">
<div class="sort-bar" id="journal-sort-bar" style="margin:0">
<span class="sort-label">Sort detailed shortlist:</span>
<button class="sort-btn active" type="button" data-sort="fit">🎯 Best fit</button>
<button class="sort-btn" type="button" data-sort="quartile">📊 Quartile</button>
<button class="sort-btn" type="button" data-sort="hindex">📈 H-index</button>
</div>
<div style="display:flex;gap:7px;align-items:center;flex-wrap:wrap">
<span class="rb-shortlist-count" id="rb-shortlist-count">0 of 5 selected</span>
<button type="button" class="rb-policy-bulk" id="rb-bulk-policy">Check policies for top 3</button>
<button type="button" class="rb-compare-open" id="rb-compare-open">Open comparison</button>
</div>
</div>
<h3 style="font-family:Georgia,serif;font-size:22px;margin:0 0 10px">🏆 Strongest verified matches</h3>
<div id="journal-cards-wrap">${(result.journals || []).map((journal, index) => rbV18RenderDetailedCard(journal, index, mode)).join("")}</div>
${rbV18RenderExtraTable(result.extended_list || [])}
<section class="rb-comparison-panel" id="rb-comparison-panel" aria-live="polite"></section>
${renderNextActions(result.next_actions, result.global_notes)}
${renderHelpCard()}
${renderJournalFinderCard()}`;
container.querySelectorAll("#journal-sort-bar .sort-btn").forEach(button => {
button.addEventListener("click", () => window.ResearchBee.sortJournalCards(button.dataset.sort || "fit", button));
});
rbV18WireDiscovery(container);
rbApplyUiLanguage(container);
container.scrollIntoView({ behavior: "smooth", block: "start" });
}
function rbV18RenderJournalResults(result, container) {
rbV18RenderDiscoveryResults(result, container, "manuscript");
}
function rbV18RenderSubjectResults(result, container) {
rbV18RenderDiscoveryResults(result, container, "subject");
}
function rbV18JournalTab() {
const form = document.getElementById("journal-form");
const results = document.getElementById("journal-results");
if (!form || !results) return;
form.addEventListener("submit", async event => {
event.preventDefault();
const manuscript = rbV18GetManuscriptData();
if (!manuscript.title || !manuscript.abstract) return;
window.ResearchBee.lastManuscript = manuscript;
RB_DISCOVERY_STATE.generation += 1;
const generation = RB_DISCOVERY_STATE.generation;
hideProgress("subject-progress");
const otherResults = document.getElementById("subject-results");
if (otherResults) { otherResults.innerHTML = ""; otherResults.classList.add("hidden"); }
const submit = form.querySelector(".btn-primary");
submit.dataset.requestGeneration = String(generation);
submit.disabled = true;
submit.textContent = rbText("Analysing verified candidates…");
results.innerHTML = "";
results.classList.remove("hidden");
showProgress("journal-progress", [
"Classifying the manuscript into verified subject fields…",
"Retrieving active journals and enforcing hard filters…",
"Checking recent article evidence and ranking fit…",
manuscript.sharing_requirement ? "Checking accepted-manuscript sharing for the strongest candidates…" : "Building the evidence-rich shortlist…",
], { requestKey: "discovery" });
try {
setStep("journal-progress", 1);
const data = await callAPI("/api/analyze-journal", { manuscript, model: getModel(), language: getLanguage() }, { requestKey: "discovery" });
if (generation !== RB_DISCOVERY_STATE.generation) return;
setStep("journal-progress", 2);
setStep("journal-progress", 3);
const apiResult = data.result || {};
if (apiResult.schema_version !== "journal_discovery_v2") {
throw new Error("ResearchBee front-end/back-end version mismatch. Refresh the page after deploying the matching backend.");
}
doneProgress("journal-progress", `[OK] ${apiResult.total || 0} verified journals shortlisted`);
rbV18RenderJournalResults(apiResult, results);
} catch (error) {
if (generation !== RB_DISCOVERY_STATE.generation || rbStaleRequest(error)) return;
failProgress("journal-progress", error);
} finally {
if (submit.dataset.requestGeneration !== String(generation)) return;
rbStopProgress("journal-progress");
submit.disabled = false;
submit.innerHTML = `<span>🔍</span> <span id="btn-journal-submit">${rbText("Find best-fit journals")}</span>`;
results.setAttribute("aria-busy", "false");
}
});
}
function rbV18SubjectTab() {
const form = document.getElementById("subject-form");
const results = document.getElementById("subject-results");
if (!form || !results) return;
form.addEventListener("submit", async event => {
event.preventDefault();
const payload = rbV18GetSubjectData();
if (!payload.subject) return;
RB_DISCOVERY_STATE.generation += 1;
const generation = RB_DISCOVERY_STATE.generation;
hideProgress("journal-progress");
const otherResults = document.getElementById("journal-results");
if (otherResults) { otherResults.innerHTML = ""; otherResults.classList.add("hidden"); }
const submit = form.querySelector(".btn-primary");
submit.dataset.requestGeneration = String(generation);
submit.disabled = true;
submit.textContent = rbText("Searching verified index…");
results.innerHTML = "";
results.classList.remove("hidden");
showProgress("subject-progress", [
"Mapping the subject to the verified ASJC/SCImago vocabulary…",
"Retrieving active journals and enforcing hard filters…",
"Checking recent article evidence and ranking subject relevance…",
payload.sharing_requirement ? "Checking accepted-manuscript sharing for the strongest candidates…" : "Building the evidence-rich shortlist…",
], { requestKey: "discovery" });
try {
setStep("subject-progress", 1);
const data = await callAPI("/api/browse-subject", payload, { requestKey: "discovery" });
if (generation !== RB_DISCOVERY_STATE.generation) return;
setStep("subject-progress", 2);
setStep("subject-progress", 3);
const apiResult = data.result || {};
if (apiResult.schema_version !== "journal_discovery_v2") {
throw new Error("ResearchBee front-end/back-end version mismatch. Refresh the page after deploying the matching backend.");
}
doneProgress("subject-progress", `[OK] ${apiResult.total || 0} verified journals shortlisted`);
rbV18RenderSubjectResults(apiResult, results);
} catch (error) {
if (generation !== RB_DISCOVERY_STATE.generation || rbStaleRequest(error)) return;
failProgress("subject-progress", error);
} finally {
if (submit.dataset.requestGeneration !== String(generation)) return;
rbStopProgress("subject-progress");
submit.disabled = false;
submit.innerHTML = `<span id="btn-subject-submit">${rbText("Find verified journals")}</span>`;
results.setAttribute("aria-busy", "false");
}
});
}
window.ResearchBee.sortJournalCards = function rbV18SortJournalCards(mode, button) {
const wrap = document.getElementById("journal-cards-wrap");
if (!wrap) return;
RB_ROOT.querySelectorAll("#journal-sort-bar .sort-btn").forEach(item => item.classList.remove("active"));
button?.classList.add("active");
const cards = Array.from(wrap.querySelectorAll(".rb-discovery-card"));
cards.sort((a, b) => {
if (mode === "quartile") return Number(a.dataset.quartile) - Number(b.dataset.quartile) || Number(b.dataset.fit) - Number(a.dataset.fit);
if (mode === "hindex") return Number(b.dataset.hindex) - Number(a.dataset.hindex) || Number(b.dataset.fit) - Number(a.dataset.fit);
return Number(b.dataset.fit) - Number(a.dataset.fit);
});
cards.forEach((card, index) => {
const rank = card.querySelector(".rb-rank-number");
if (rank) rank.textContent = `#${index + 1}`;
wrap.appendChild(card);
});
};
// Assign before the shared initialisation calls below. This prevents the legacy
// independent renderers from attaching handlers, while preserving all shared
// licence, repository, chat, cover-letter and related-works helpers.
getManuscriptData = rbV18GetManuscriptData;
renderJournalResults = rbV18RenderJournalResults;
renderSubjectResults = rbV18RenderSubjectResults;
journalTab = rbV18JournalTab;
subjectTab = rbV18SubjectTab;
// One display dictionary. Select values and source records retain API/original values.
const RB_CHAT_WELCOME_AR = "مرحباً! أنا ResearchBee، مساعد مكتبة جامعة خليفة للنشر وإدارة بيانات البحث. يمكنني مساعدتك في اختيار المجلات والتحقق منها، وفهم دعم النشر والوصول المفتوح وحقوق مشاركة المقالات، واختيار مستودعات البيانات. كيف يمكنني مساعدتك؟";
const RB_UI_ORIGINAL_TEXT = new WeakMap();
const RB_UI_STRINGS = {
"Share feedback": "شاركنا ملاحظاتك",
"View journal details": "عرض تفاصيل المجلة",
"Hide journal details": "إخفاء تفاصيل المجلة",
"Ranking source and verification:": "مصدر التصنيف وحالة التحقق:",
"Find a home for your research data": "اعثر على مستودع مناسب لبيانات بحثك",
"Find a suitable repository in two simple steps.": "اعثر على مستودع مناسب في خطوتين بسيطتين.",
"Describe your dataset": "صِف مجموعة بياناتك",
"Tell us about your data, research field, file formats and approximate size.": "أخبرنا عن بياناتك ومجال بحثك وصيغ الملفات وحجمها التقريبي.",
"Set your sharing requirements": "حدّد متطلبات مشاركة بياناتك",
"Choose access, licence and deposit requirements to find suitable repositories.": "اختر متطلبات الوصول والترخيص والإيداع للعثور على مستودعات مناسبة.",
"Start: describe your dataset": "ابدأ بوصف مجموعة بياناتك",
"Back to data repository overview": "العودة إلى نظرة عامة على مستودعات البيانات",
"Step 1 of 2": "الخطوة 1 من 2",
"Step 2 of 2": "الخطوة 2 من 2",
"Enter the basic details so ResearchBee can identify suitable repositories.": "أدخل التفاصيل الأساسية ليتمكن ResearchBee من تحديد المستودعات المناسبة.",
"Review access, licences and deposit requirements, then find suitable repositories.": "راجع متطلبات الوصول والتراخيص والإيداع، ثم ابحث عن مستودعات مناسبة.",
"Next: sharing requirements": "التالي: متطلبات المشاركة",
"Back to dataset details": "العودة إلى تفاصيل مجموعة البيانات",
"How would you like to check sharing permissions?": "كيف تود التحقق من صلاحيات المشاركة؟",
"Check a specific article or explore a journal's sharing policy.": "تحقق من مقالة محددة أو استكشف سياسة المشاركة لإحدى المجلات.",
"Check a specific article": "تحقق من مقالة محددة",
"Use a DOI or article URL to check sharing permissions and whether your article is in Khazna.": "استخدم معرّف DOI أو رابط المقالة للتحقق من صلاحيات المشاركة ووجود مقالتك في خزنة.",
"Check my article": "تحقق من مقالتي",
"Check a journal's sharing policy": "تحقق من سياسة المشاركة للمجلة",
"Use a journal name or ISSN to explore publisher policies on sharing article versions.": "استخدم اسم المجلة أو رقم ISSN لاستكشاف سياسات الناشر بشأن مشاركة نسخ المقالة.",
"Check a journal policy": "تحقق من سياسة المجلة",
"Back to sharing options": "العودة إلى خيارات المشاركة",
"Check article-sharing permissions": "تحقق من صلاحيات مشاركة المقالة",
"Review which version you may share, where you may deposit it, and any conditions that apply.": "راجع النسخة التي يمكنك مشاركتها ومكان إيداعها والشروط التي تنطبق عليها.",
"Article version, deposit location and other preferences": "نسخة المقالة ومكان الإيداع والتفضيلات الأخرى",
"Enter a journal name or ISSN to continue.": "أدخل اسم المجلة أو رقم ISSN للمتابعة.",
"Enter an article DOI or URL to continue.": "أدخل معرّف DOI أو رابط المقالة للمتابعة.",
"Choose a function": "اختر إحدى الوظائف",
"Clear all & return home": "مسح الكل والعودة إلى البداية",
"Select a function above to get started.": "اختر إحدى الوظائف أعلاه للبدء.",
"Choose one of two options": "اختر أحد الخيارين",
"Start with your research subject or use your manuscript.": "ابدأ بموضوع بحثك أو استخدم مخطوطتك.",
"Enter your research subject to explore and compare suitable journals.": "أدخل موضوع بحثك لاستكشاف المجلات المناسبة والمقارنة بينها.",
"Browse journals by subject": "تصفح المجلات حسب الموضوع",
"Analyse your manuscript": "حلّل مخطوطتك",
"Enter your title and abstract to find journals that match your manuscript.": "أدخل عنوان مخطوطتك وملخصها للعثور على مجلات مناسبة لها.",
"Find journals for my manuscript": "ابحث عن مجلات مناسبة لمخطوطتي",
"Back to journal options": "العودة إلى خيارات البحث عن المجلات",
"AI assistance uses external services. Do not enter confidential manuscripts or identifiable personal or health data.": "تستخدم المساعدة بالذكاء الاصطناعي خدمات خارجية. لا تُدخل مخطوطات سرية أو بيانات شخصية أو صحية تكشف الهوية.",
"How your information is used": "كيف تُستخدم معلوماتك",
"Your manuscript, dataset description and chat messages may be sent to OpenAI to provide AI assistance. OpenAlex receives subject keywords to identify suitable journals using related article evidence. Policy checks send journal identifiers or the DOI to the relevant services. Describe sensitive datasets without sharing their contents. Contact KU Library for help with confidential research.": "قد تُرسل مخطوطتك ووصف مجموعة البيانات ورسائل الدردشة إلى OpenAI لتقديم المساعدة بالذكاء الاصطناعي. يتلقى OpenAlex كلمات مفتاحية لتحديد المجلات المناسبة بالاستناد إلى مقالات ذات صلة. تُرسل معرّفات المجلات أو معرّف DOI إلى الخدمات المعنية للتحقق من السياسات. صِف مجموعات البيانات الحساسة دون مشاركة محتواها. تواصل مع مكتبة الجامعة للمساعدة في الأبحاث السرية.",
"Khalifa University Library": "مكتبة جامعة خليفة",
"Your publication support assistant": "مساعدك لدعم النشر العلمي",
"Helping you publish and share your research.": "نساعدك على نشر أبحاثك ومشاركتها.",
"Find suitable journals for your article": "اعثر على مجلات مناسبة لمقالتك",
"Identify and compare journals that match your research.": "تعرّف على المجلات المناسبة لبحثك وقارن بينها.",
"Check whether you can share your article": "تحقق من إمكانية مشاركة مقالتك",
"Review publisher policies, article versions, licences, and waiting periods before repository deposit.": "راجع سياسات الناشر ونسخ المقالة والتراخيص وفترات الحظر قبل الإيداع في المستودع.",
"Find a research data repository": "اعثر على مستودع لبيانات البحث",
"Explore suitable repositories for storing and sharing your research data.": "استكشف مستودعات مناسبة لحفظ بيانات بحثك ومشاركتها.",
"Looking for articles to read?": "هل تبحث عن مقالات لقراءتها؟",
"ResearchBee is not an article search tool. Use LibBee or Library Primo to find articles.": "ResearchBee ليس أداة للبحث عن المقالات. استخدم LibBee أو Primo المكتبة للعثور على المقالات.",
"Library Primo": "Primo المكتبة",
"About ResearchBee": "عن ResearchBee",
...Object.fromEntries(Object.values(TRANSLATIONS).map(item => [item.en, item.ar])),
"Register your publication with Khazna. Deposit a manuscript file only when the checked version, repository location, licence and embargo conditions permit it; contact KU Library when permission is unclear.": "سجّل منشورك في خزنة. أودع ملف المخطوطة فقط عندما تسمح بذلك الشروط المتحقق منها بشأن النسخة وموقع المستودع والرخصة وحظر النشر؛ تواصل مع مكتبة الجامعة عندما يكون الإذن غير واضح.",
"Not found in loaded snapshot": "لم يُعثر عليه في لقطة البيانات المحمّلة",
"Found in loaded snapshot": "عُثر عليه في لقطة البيانات المحمّلة",
"This DOI was not found in the loaded Khazna snapshot. Confirm in the live portal before creating another record.": "لم يُعثر على معرّف DOI هذا في لقطة بيانات خزنة المحمّلة. تحقق من البوابة الحالية قبل إنشاء سجل آخر.",
"Candidates excluded by requirement checks": "مرشحون استُبعدوا بعد التحقق من المتطلبات",
"These candidates were removed from the recommendations after checking your requirements. Review the reasons when refining your search.": "استُبعد هؤلاء المرشحون من التوصيات بعد التحقق من متطلباتك. راجع الأسباب عند تعديل البحث.",
"Still unverified:": "لم يُتحقق بعد من:", "Here are repository options and the requirement checks for your dataset.": "إليك خيارات المستودعات ونتائج التحقق من متطلبات مجموعة البيانات الخاصة بك.",
"Verify on:": "تحقق عبر:", "Criterion": "المعيار", "⬇ Download .txt": "⬇ تنزيل ملف نصي", "📋 Copy": "📋 نسخ",
"No destination is verified for file deposit. Review the requirements with KU Library.": "لم يُتحقق من وجهة لإيداع الملفات. راجع المتطلبات مع مكتبة الجامعة.",
"Candidate repositories need manual review before depositing files.": "تحتاج المستودعات المرشحة إلى مراجعة يدوية قبل إيداع الملفات.",
"Chat messages are sent to OpenAI. Do not share confidential or personal data.": "تُرسل رسائل المحادثة إلى OpenAI. لا تشارك بيانات سرية أو شخصية.",
"Classifying the manuscript into verified subject fields…": "جارٍ تصنيف المخطوطة ضمن مجالات موضوعية متحقق منها…",
"Retrieving active journals and enforcing hard filters…": "جارٍ استرجاع المجلات النشطة وتطبيق شروط التصفية…",
"Checking recent article evidence and ranking fit…": "جارٍ فحص أدلة المقالات الحديثة وترتيب الملاءمة…",
"Checking accepted-manuscript sharing for the strongest candidates…": "جارٍ التحقق من مشاركة المخطوطة المقبولة لدى أقوى المرشحين…",
"Building the evidence-rich shortlist…": "جارٍ إعداد القائمة المختصرة المدعومة بالأدلة…",
"Mapping the subject to the verified ASJC/SCImago vocabulary…": "جارٍ مطابقة الموضوع مع مفردات ASJC/SCImago المتحقق منها…",
"Checking recent article evidence and ranking subject relevance…": "جارٍ فحص المقالات الحديثة وترتيب الصلة بالموضوع…",
"Analysing your dataset...": "جارٍ تحليل وصف مجموعة البيانات...", "Matching repositories...": "جارٍ مطابقة المستودعات...", "Building recommendations...": "جارٍ إعداد التوصيات...",
"Resolving DOI...": "جارٍ التحقق من DOI...", "Resolving the journal record...": "جارٍ التحقق من سجل المجلة...", "Checking OA.Works Permissions + Khazna...": "جارٍ التحقق من أذونات OA.Works وخزنة...",
"Querying the Jisc Open Policy Finder API...": "جارٍ الاستعلام من Jisc Open Policy Finder...", "Building deposit guidance...": "جارٍ إعداد إرشادات الإيداع...", "Preparing the journal-level policy options...": "جارٍ إعداد خيارات سياسة المجلة...",
"Language:": "اللغة:", "Publishing and research data, made clearer.": "دعم أوضح للنشر وبيانات البحث.",
"Find your journal": "اعثر على مجلتك", "Share your article": "شارك مقالتك", "Deposit your data": "أودع بياناتك",
"Journal fit, rankings & OA options": "ملاءمة المجلة وتصنيفاتها وخيارات الوصول المفتوح", "Deposit rights & KU repository": "حقوق الإيداع ومستودع الجامعة", "Find the right repository": "اعثر على المستودع المناسب",
"Browse by subject": "تصفح حسب الموضوع", "Analyse manuscript": "حلل المخطوطة", "Advanced journal preferences": "تفضيلات المجلات المتقدمة",
"Advanced journal preferences and manuscript context": "تفضيلات المجلات المتقدمة وسياق المخطوطة", "Quartile filter": "تصفية حسب الربع التصنيفي",
"Journal access model": "نموذج الوصول إلى المجلة", "Accepted manuscript must be depositable in a repository": "يجب أن يُسمح بإيداع المخطوطة المقبولة في مستودع",
"Intended repository": "المستودع المقصود", "planning only": "للتخطيط فقط", "Preferred journals": "المجلات المفضلة", "Journals to exclude": "المجلات المستبعدة",
"Keywords": "الكلمات المفتاحية", "Methods": "المنهجية", "No filter": "بدون تصفية", "Q1 or Q2": "Q1 أو Q2", "Any journal": "أي مجلة",
"Open-access journals": "مجلات الوصول المفتوح", "Diamond / no APC": "وصول ماسي / بدون رسوم نشر", "Institutional repository": "مستودع مؤسسي",
"Subject repository": "مستودع تخصصي", "Both institutional & subject": "مستودع مؤسسي وتخصصي", "Not sure": "غير متأكد",
"Original research article": "مقالة بحثية أصلية", "Review article": "مقالة مراجعة", "Systematic review / meta-analysis": "مراجعة منهجية / تحليل تلوي",
"Short communication": "مراسلة بحثية قصيرة", "Case study": "دراسة حالة", "Methods paper": "ورقة منهجية", "Perspective / commentary": "وجهة نظر / تعليق", "Letter": "رسالة", "Conference paper": "ورقة مؤتمر",
"All versions": "جميع النسخ", "Submitted version / preprint": "النسخة المقدمة / ما قبل النشر", "Accepted manuscript (AAM / postprint)": "المخطوطة المقبولة (AAM)", "Published version (VoR)": "النسخة المنشورة (VoR)",
"Subject repository (e.g. arXiv, PMC, SSRN)": "مستودع تخصصي (مثل arXiv أو PMC أو SSRN)", "Personal website": "موقع شخصي", "Preprint server": "خادم ما قبل النشر", "Publisher's bespoke licence": "رخصة الناشر الخاصة",
"Yes": "نعم", "No": "لا", "Unsure": "غير متأكد", "Open": "مفتوح", "Restricted": "مقيد", "Sensitive": "حساس", "Mixed": "مختلط",
"Yes — anonymised": "نعم — مجهولة الهوية", "Yes — pseudonymised": "نعم — مستعارة الهوية", "Yes — identifiable": "نعم — قابلة لتحديد الهوية", "Restricted / custom": "مقيدة / مخصصة",
"Embargo duration (months, optional)": "مدة الحظر (بالأشهر، اختياري)", "Enter a duration only when an embargo is required.": "أدخل المدة فقط عند الحاجة إلى حظر النشر.",
"Sensitivity & access": "الحساسية والوصول", "Context": "السياق", "Article DOI or URL": "معرّف DOI أو رابط المقالة", "recommended — gives a verified answer": "موصى به — للتحقق على مستوى المقالة",
"Journal name": "اسم المجلة", "ISSN (optional — improves accuracy)": "الرقم الدولي ISSN (اختياري — يحسّن الدقة)",
"📊 Browse verified journals by subject": "📊 تصفح المجلات المتحقق منها حسب الموضوع", "📰 Match a manuscript to verified journals": "📰 طابق المخطوطة مع المجلات المتحقق منها",
"🛡 Share your published article": "🛡 شارك مقالتك المنشورة", "🗄 Find a research data repository": "🗄 اعثر على مستودع لبيانات البحث",
"Find verified journals": "اعثر على مجلات متحقق منها", "Find best-fit verified journals": "اعثر على أنسب المجلات المتحقق منها", "Find best-fit journals": "اعثر على أنسب المجلات", "Check Green OA policy": "تحقق من سياسة الإيداع في المستودعات", "Find best repositories": "اعثر على أفضل المستودعات",
"Analysing verified candidates…": "جارٍ تحليل المجلات المرشحة المتحقق منها…", "Searching verified index…": "جارٍ البحث في الفهرس المتحقق منه…",
"🔍 Checking policy...": "🔍 جارٍ التحقق من السياسة...", "Finding repositories...": "جارٍ البحث عن المستودعات...",
"Edit search": "تعديل البحث", "↩ Start over": "↩ ابدأ من جديد", "Start over": "ابدأ من جديد", "Add to comparison": "أضف إلى المقارنة", "Compare": "قارن",
"Check policy": "تحقق من السياسة", "Check sharing policy": "تحقق من سياسة المشاركة", "Refresh policy": "تحديث السياسة", "Policy checked": "تم التحقق من السياسة", "Checking…": "جارٍ التحقق…",
"Check policies for top 3": "تحقق من سياسات أفضل ثلاث مجلات", "Open comparison": "افتح المقارنة", "Journal decision table": "جدول المقارنة لاتخاذ القرار", "Export CSV": "تصدير CSV", "Clear shortlist": "مسح القائمة المختصرة",
"Sort detailed shortlist:": "ترتيب القائمة التفصيلية:", "🎯 Best fit": "🎯 أفضل ملاءمة", "📊 Quartile": "📊 الربع التصنيفي", "📈 H-index": "📈 مؤشر H",
"Manuscript journal analysis": "تحليل المجلات للمخطوطة", "Subject journal discovery": "استكشاف المجلات حسب الموضوع", "🏆 Strongest verified matches": "🏆 أقوى المطابقات المتحقق منها",
"No journal met every selected hard filter": "لم تستوفِ أي مجلة جميع شروط التصفية المحددة", "No verified journal match found": "لم تُعثر على مجلة مطابقة متحقق منها",
"Journal analysis could not be completed": "تعذر إكمال تحليل المجلات", "Subject search could not be completed": "تعذر إكمال البحث حسب الموضوع",
"Review or correct inferred details": "راجع أو صحح التفاصيل المستنتجة", "Analyse this journal with a manuscript": "حلل هذه المجلة باستخدام مخطوطة", "Analyse manuscript": "تحليل المخطوطة",
"✉ Generate cover letter": "✉ إنشاء خطاب التقديم", "Generating...": "جارٍ الإنشاء...", "Writing cover letter...": "جارٍ كتابة خطاب التقديم...",
"Draft only. Verify every claim and complete author confirmations for originality, approval, conflicts of interest and ethics before sending.": "مسودة فقط. تحقق من جميع الادعاءات وأكمل تأكيدات المؤلفين بشأن الأصالة والموافقة وتضارب المصالح والأخلاقيات قبل الإرسال.",
"📄 Related works in this journal": "📄 أبحاث ذات صلة في هذه المجلة", "Highly cited": "الأكثر استشهاداً", "Citation chain": "سلسلة الاستشهادات", "See who cites this →": "اطلع على الأبحاث التي تستشهد بهذا →",
"Before you submit:": "قبل الإرسال:",
"Your manuscript, dataset description and chat messages may be sent to OpenAI to provide AI assistance. OpenAlex receives subject keywords for article discovery. Do not paste confidential manuscripts or identifiable personal or health data. Describe sensitive datasets without sharing their contents. Policy checks send journal identifiers or the DOI to the relevant services. Contact KU Library for help with confidential research.": "قد تُرسل مخطوطتك ووصف مجموعة البيانات ورسائل المحادثة إلى OpenAI لتقديم المساعدة. يتلقى OpenAlex كلمات موضوعية للبحث عن المقالات. لا تلصق مخطوطات سرية أو بيانات شخصية أو صحية قابلة لتحديد الهوية. صف مجموعات البيانات الحساسة دون مشاركة محتوياتها. ترسل عمليات التحقق من السياسات معرّفات المجلة أو DOI إلى الخدمات المعنية. تواصل مع مكتبة الجامعة للحصول على دعم للبحوث السرية.",
"Need help?": "هل تحتاج إلى مساعدة؟", "Chat with ResearchBee": "تحدث مع ResearchBee", "Clear": "مسح", "Send message": "إرسال رسالة", "Close chat": "إغلاق المحادثة",
"How do I choose the best journal?": "كيف أختار المجلة الأنسب؟", "What does Q1 or CiteScore percentile mean?": "ما معنى Q1 أو النسبة المئوية لـ CiteScore؟", "Does KU cover my APC?": "هل تغطي جامعة خليفة رسوم النشر؟", "How do I choose a data repository?": "كيف أختار مستودعاً للبيانات؟",
"Metadata registration only": "تسجيل البيانات الوصفية فقط", "Review required before file deposit": "تلزم مراجعة قبل إيداع الملفات", "Repository requirement checks": "التحقق من متطلبات المستودع",
"Register metadata with KU Library. Dataset file hosting, DOI assignment, embargo and versioning need separate confirmation.": "سجّل البيانات الوصفية لدى مكتبة الجامعة. تحتاج استضافة ملفات البيانات وتخصيص DOI والحظر وإدارة الإصدارات إلى تأكيد منفصل.",
"File deposit is not recommended until the repository and KU Library confirm the requirements for this dataset.": "لا يُوصى بإيداع الملفات قبل تأكيد المستودع ومكتبة الجامعة متطلبات مجموعة البيانات هذه.",
"Sensitive-data review required. Do not upload identifiable or confidential files.": "تلزم مراجعة البيانات الحساسة. لا ترفع ملفات سرية أو قابلة لتحديد الهوية.", "Capability record reviewed:": "تاريخ مراجعة سجل الإمكانات:",
"Selected context appears compatible": "يبدو السياق المحدد متوافقاً", "Conditional — review the applicable option": "مشروط — راجع الخيار المنطبق", "Selected context is not permitted by the assessed options": "لا تسمح الخيارات المقيمة بالسياق المحدد", "Selected-context applicability is unknown": "مدى انطباق السياسة على السياق المحدد غير معلوم",
"Policy result": "نتيجة التحقق من السياسة", "🟢 Green OA / self-archiving by version": "🟢 الإيداع الذاتي حسب نسخة المقالة", "Where": "مكان الإيداع", "Embargo": "حظر النشر", "Licence": "الرخصة", "Conditions": "الشروط",
"🗂 Dataset understanding": "🗂 فهم مجموعة البيانات", "Deposit strategy": "استراتيجية الإيداع", "Primary choice": "الخيار الأول", "Secondary choice": "الخيار الثاني", "Metadata standard": "معيار البيانات الوصفية",
"Journal": "المجلة", "Publisher": "الناشر", "Fit": "الملاءمة", "Matched field": "المجال المطابق", "Access": "الوصول", "Shortlist & policy": "القائمة والسياسة", "Fit score": "درجة الملاءمة",
"Why this fit score was assigned": "سبب تحديد درجة الملاءمة", "🎯 Why it fits": "🎯 سبب الملاءمة", "👥 Audience match": "👥 ملاءمة الجمهور", "📋 Submission strategy": "📋 استراتيجية التقديم", "🔓 Open Access planning": "🔓 التخطيط للوصول المفتوح",
"🔓 Journal access model": "🔓 نموذج الوصول إلى المجلة", "🎓 KU APC planning": "🎓 التخطيط لدعم رسوم النشر بالجامعة", "🛡 Sharing policy": "🛡 سياسة المشاركة", "📄 Recent article evidence": "📄 أدلة من المقالات الحديثة",
"Open public record search": "افتح البحث في السجل العام", "Copy": "نسخ", "Copied!": "تم النسخ!", "Download TXT": "تنزيل TXT", "Download": "تنزيل",
};
Object.assign(RB_UI_STRINGS, {"More repositories from re3data.org": "مستودعات إضافية من re3data.org", "Not reviewed by KU Library": "لم تراجعها مكتبة جامعة خليفة", "Search re3data.org yourself": "ابحث في re3data.org بنفسك", "re3data record": "سجل re3data", "Subjects": "المجالات", "Data upload": "رفع البيانات", "Data access": "الوصول إلى البيانات", "Certificates": "الشهادات", "Country": "الدولة", "No additional re3data repositories were found.": "لم يُعثر على مستودعات إضافية في re3data.", "The recommendations above come from the KU Library curated registry; use these listings to widen your options and confirm every detail with the repository.": "التوصيات أعلاه مأخوذة من السجل المعتمد لدى مكتبة جامعة خليفة؛ استخدم هذه القوائم لتوسيع خياراتك وتحقق من كل التفاصيل لدى المستودع."});
Object.assign(RB_UI_STRINGS, {"Journal website": "موقع المجلة", "Author guidelines": "إرشادات المؤلفين", "Find author guidelines": "البحث عن إرشادات المؤلفين", "Not available": "غير متاح", "Metadata only": "بيانات وصفية فقط", "Checked": "تم التحقق", "Curated": "مختار من السجل", "Source": "المصدر", "Journal-specific instructions": "إرشادات خاصة بالمجلة", "General publisher guidance": "إرشادات عامة للناشر", "Journal links": "روابط المجلة", "Visit repository": "زيارة المستودع", "Quartile by field": "الربع حسب التخصص", "Checking official publisher page…": "جارٍ فحص صفحة الناشر الرسمية…", "Author guidance unavailable; use the journal website if available.": "إرشادات المؤلفين غير متاحة؛ استخدم موقع المجلة إن توفر.", "The lookup failed. The journal website remains available; try again later.": "تعذر البحث. يبقى موقع المجلة متاحًا؛ حاول لاحقًا.", "Each quartile belongs to its own category. SCImago SJR is separate from Scopus CiteScore.": "كل ربع يخص فئته فقط. تصنيف SCImago SJR منفصل عن Scopus CiteScore."});
function rbText(text) { return getLanguage() === "arabic" ? (RB_UI_STRINGS[text] || text) : text; }
function rbApplyUiLanguage(scope = RB_ROOT) {
if (!scope) return;
const isArabic = getLanguage() === "arabic";
scope.querySelectorAll("select option").forEach(option => {
if (!option.dataset.rbEnglish) { option.dataset.rbEnglish = option.textContent; if (!option.hasAttribute("value")) option.value = option.textContent; }
const next = isArabic ? (RB_UI_STRINGS[option.dataset.rbEnglish] || option.dataset.rbEnglish) : option.dataset.rbEnglish;
if (option.textContent !== next) option.textContent = next;
});
const walker = document.createTreeWalker(scope, NodeFilter.SHOW_TEXT);
while (walker.nextNode()) {
const node = walker.currentNode;
if (!node.parentElement || node.parentElement.closest("script, style, textarea, option, pre, .ds-body, .rb-bubble, .rw-title, .rw-authors")) continue;
const original = RB_UI_ORIGINAL_TEXT.get(node) ?? node.nodeValue;
const trimmed = original.trim();
if (!Object.prototype.hasOwnProperty.call(RB_UI_STRINGS, trimmed)) continue;
RB_UI_ORIGINAL_TEXT.set(node, original);
const value = isArabic ? original.replace(trimmed, RB_UI_STRINGS[trimmed]) : original;
if (node.nodeValue !== value) node.nodeValue = value;
}
}
function rbTrapFocus(container, event) {
const controls = Array.from(container.querySelectorAll('button:not([disabled]), a[href], input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex="0"]')).filter(element => !element.hidden && element.getClientRects().length);
if (!controls.length) { event.preventDefault(); container.focus(); return; }
const first = controls[0], last = controls[controls.length - 1];
if (event.shiftKey && (document.activeElement === first || document.activeElement === container)) { event.preventDefault(); last.focus(); }
else if (!event.shiftKey && (document.activeElement === last || document.activeElement === container)) { event.preventDefault(); first.focus(); }
}
function rbInitialiseAccessibility() {
const tabs = Array.from(RB_ROOT.querySelectorAll(".tab-btn"));
RB_ROOT.querySelector(".tabs-inner")?.setAttribute("role", "tablist");
RB_ROOT.querySelector(".tabs-inner")?.setAttribute("aria-labelledby", "rb-functions-title");
tabs.forEach(button => {
button.id = `rb-tab-${button.dataset.tab}`;
button.setAttribute("role", "tab"); button.setAttribute("aria-controls", `tab-${button.dataset.tab}`);
const panel = document.getElementById(`tab-${button.dataset.tab}`);
panel?.setAttribute("role", "tabpanel"); panel?.setAttribute("aria-labelledby", button.id);
button.addEventListener("keydown", event => rbTabKeys(event, tabs, current => activateTab(current.dataset.tab)));
});
RB_ROOT.querySelectorAll(".mode-btn").forEach(button => {
button.id = `rb-mode-${button.dataset.mode}`;
button.setAttribute("aria-controls", `mode-${button.dataset.mode}`);
const panel = document.getElementById(`mode-${button.dataset.mode}`);
panel?.setAttribute("role", "region"); panel?.setAttribute("aria-labelledby", button.id);
});
["journal", "subject", "license", "repo"].forEach(prefix => {
const progress = document.getElementById(`${prefix}-progress`);
progress?.setAttribute("role", "status"); progress?.setAttribute("aria-live", "polite"); progress?.setAttribute("aria-atomic", "true");
document.getElementById(`${prefix}-results`)?.setAttribute("aria-busy", "false");
});
["rb-chat-launcher", "rb-mobile-chat-bar"].forEach(id => { const button = document.getElementById(id); button?.setAttribute("aria-controls", "rb-chat-panel"); button?.setAttribute("aria-expanded", "false"); });
const backdrop = document.getElementById("rb-service-intro-backdrop"); if (backdrop) backdrop.inert = true;
const embargo = document.getElementById("r-embargo"), months = document.getElementById("r-embargo-months");
embargo?.addEventListener("change", () => { if (months) { months.disabled = embargo.value !== "Yes"; if (months.disabled) months.value = ""; } });
document.getElementById("repo-form")?.addEventListener("reset", () => { if (months) months.disabled = true; });
["j-abstract", "r-desc", "l-notes", "r-notes"].forEach(id => {
const input = document.getElementById(id); if (!input) return;
const counter = document.createElement("span"); counter.id = `${id}-count`; counter.className = "rb-character-count";
input.insertAdjacentElement("afterend", counter); input.setAttribute("aria-describedby", `${input.getAttribute("aria-describedby") || ""} ${counter.id}`.trim());
const update = () => { counter.textContent = `${input.value.length} / ${input.maxLength}`; };
input.addEventListener("input", update); input.form?.addEventListener("reset", () => setTimeout(update, 0)); update();
});
rbShowHome(false);
}
function rbTabKeys(event, tabs, activate) {
if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) return;
event.preventDefault(); const index = tabs.indexOf(event.currentTarget);
const rtl = RB_ROOT.dir === "rtl", step = (event.key === "ArrowRight" ? 1 : -1) * (rtl ? -1 : 1);
const next = event.key === "Home" ? 0 : event.key === "End" ? tabs.length - 1 : (index + step + tabs.length) % tabs.length;
activate(tabs[next]); tabs[next].focus();
}
// Article and journal policy checks have separate entry screens.
function rbSetShareMode(mode, focus = false) {
const next = ["article", "journal"].includes(mode) ? mode : "";
rbCancelRequest("license");
rbCancelRequest("journal-lookup");
clearTimeout(_lookupTimer); _lookupTimer = null;
rbResetFormUi("license");
RB_ROOT.dataset.rbShareMode = next;
document.getElementById("rb-share-choices").hidden = Boolean(next);
document.getElementById("rb-share-work").hidden = !next;
document.querySelector("#license-form .doi-primary").hidden = next !== "article";
document.getElementById("rb-share-journal-fields").hidden = next !== "journal";
const title = document.getElementById("rb-share-form-title");
title.textContent = rbText(next === "journal" ? "Check a journal's sharing policy" : "Check a specific article");
rbUpdateDataNotice();
if (focus) rbFocusWorkflow(next ? title : document.getElementById("rb-share-choice-title"));
}
function rbShowShareChoices(focus = false) { rbSetShareMode("", focus); }
function rbInitSharingChoices() {
RB_ROOT.querySelectorAll(".rb-share-choice").forEach(button => {
button.addEventListener("click", () => rbSetShareMode(button.dataset.shareMode, true));
});
document.getElementById("rb-share-back")?.addEventListener("click", () => rbShowShareChoices(true));
}
// Clear all returns to the service chooser without reloading LibGuides.
function rbResetFormUi(prefix) {
hideProgress(`${prefix}-progress`);
document.getElementById(`${prefix}-progress`)?.replaceChildren();
const results = document.getElementById(`${prefix}-results`);
if (results) {
results.replaceChildren(); results.classList.add("hidden");
results.setAttribute("aria-busy", "false");
}
const form = document.getElementById(`${prefix}-form`);
const labels = {
subject: '<span id="btn-subject-submit">Find verified journals</span>',
journal: '<span aria-hidden="true">🔍</span> <span id="btn-journal-submit">Find best-fit journals</span>',
license: '<span aria-hidden="true">🛡</span> <span>Check Green OA policy</span>',
repo: '<span aria-hidden="true">🗄</span> <span id="btn-repo-submit">Find best repositories</span>',
};
form?.querySelectorAll('.btn-primary[type="submit"]').forEach(button => {
button.disabled = false;
delete button.dataset.requestGeneration;
button.innerHTML = labels[prefix] || button.innerHTML;
});
form?.querySelectorAll("details").forEach(details => { details.open = false; });
if (form) rbApplyUiLanguage(form);
}
function rbClearAll() {
rbCancelAllRequests();
clearTimeout(_lookupTimer); _lookupTimer = null;
RB_DISCOVERY_STATE.generation += 1;
RB_DISCOVERY_STATE.mode = "";
RB_DISCOVERY_STATE.result = null;
RB_DISCOVERY_STATE.all = [];
RB_DISCOVERY_STATE.byKey.clear();
RB_DISCOVERY_STATE.selected.clear();
RB_DISCOVERY_STATE.container = null;
RB_DISCOVERY_STATE.context = { funder: "", intended_repository: "Institutional repository" };
RB_COVER_LETTER_PAYLOADS.clear();
RB_RELATED_WORK_PAYLOADS.clear();
RB_SUBJECT_JOURNAL_PAYLOADS.clear();
delete window.ResearchBee.lastManuscript;
["subject", "journal", "license", "repo"].forEach(prefix => {
document.getElementById(`${prefix}-form`)?.reset();
rbResetFormUi(prefix);
});
window.ResearchBee.clearAutofill();
document.getElementById("analyse-notice")?.remove();
RB_ROOT.querySelectorAll("details").forEach(details => { details.open = false; });
RB_ROOT.querySelectorAll("[data-autofilled]").forEach(field => { delete field.dataset.autofilled; });
window.ResearchBee.resetChat?.();
document.getElementById("rb-service-intro-close")?.click();
rbShowHome(true);
}
window.ResearchBee.clearAll = rbClearAll;
function rbInitResetControls() {
document.getElementById("rb-clear-all")?.addEventListener("click", rbClearAll);
["subject", "journal"].forEach(prefix => {
document.getElementById(`${prefix}-form`)?.addEventListener("reset", () => {
rbCancelRequest("discovery");
RB_DISCOVERY_STATE.generation += 1;
rbResetFormUi(prefix);
});
});
}
// The repository payload stays unchanged; only one form section is visible.
function rbShowRepositoryIntro(focus = false) {
RB_ROOT.dataset.rbRepoStep = "";
const intro = document.getElementById("rb-repo-intro");
if (intro) intro.hidden = false;
const form = document.getElementById("repo-form");
if (form) form.hidden = true;
const back = document.getElementById("rb-repo-back-wrap");
if (back) back.hidden = true;
["repo-progress", "repo-results"].forEach(id => {
const element = document.getElementById(id); if (element) element.hidden = true;
});
rbUpdateDataNotice();
if (focus) rbFocusWorkflow(document.getElementById("rb-repo-intro-title"));
}
function rbSetRepositoryStep(step, focus = false) {
const next = String(step) === "2" ? "2" : "1";
RB_ROOT.dataset.rbRepoStep = next;
const intro = document.getElementById("rb-repo-intro");
if (intro) intro.hidden = true;
const form = document.getElementById("repo-form");
if (form) form.hidden = false;
const back = document.getElementById("rb-repo-back-wrap");
if (back) back.hidden = false;
["1", "2"].forEach(number => {
const section = document.getElementById(`rb-repo-stage-${number}`);
if (section) section.hidden = number !== next;
});
["repo-progress", "repo-results"].forEach(id => {
const element = document.getElementById(id); if (element) element.hidden = next !== "2";
});
const content = next === "1"
? ["Step 1 of 2", "Describe your dataset", "Enter the basic details so ResearchBee can identify suitable repositories."]
: ["Step 2 of 2", "Set your sharing requirements", "Review access, licences and deposit requirements, then find suitable repositories."];
["rb-repo-step-label", "rb-repo-step-title", "rb-repo-step-description"].forEach((id, index) => {
const element = document.getElementById(id); if (element) element.textContent = content[index];
});
rbApplyUiLanguage(form);
rbUpdateDataNotice();
if (focus) rbFocusWorkflow(document.getElementById("rb-repo-step-title"));
}
function rbValidateRepositoryFields(scope) {
const invalid = Array.from(scope?.querySelectorAll("input, select, textarea") || [])
.find(field => field.willValidate && !field.validity.valid);
if (!invalid) return true;
rbSetRepositoryStep(invalid.closest("#rb-repo-stage-1") ? "1" : "2");
invalid.reportValidity();
invalid.focus();
return false;
}
function rbAdvanceRepositoryStep() {
if (rbValidateRepositoryFields(document.getElementById("rb-repo-stage-1"))) rbSetRepositoryStep("2", true);
}
function rbInitialiseRepositorySteps() {
const form = document.getElementById("repo-form");
if (!form) return;
document.getElementById("rb-repo-start")?.addEventListener("click", () => rbSetRepositoryStep("1", true));
document.getElementById("rb-repo-next")?.addEventListener("click", rbAdvanceRepositoryStep);
document.getElementById("rb-repo-previous")?.addEventListener("click", () => rbSetRepositoryStep("1", true));
document.getElementById("rb-repo-back-options")?.addEventListener("click", () => rbShowRepositoryIntro(true));
form.addEventListener("keydown", event => {
if (event.key !== "Enter" || event.isComposing || event.target.tagName === "TEXTAREA") return;
if (RB_ROOT.dataset.rbRepoStep !== "1" || !event.target.matches("input, select")) return;
event.preventDefault(); rbAdvanceRepositoryStep();
});
// Capture runs before the existing repository submission handler.
form.addEventListener("submit", event => {
if (RB_ROOT.dataset.rbRepoStep !== "2") {
event.preventDefault(); event.stopImmediatePropagation();
if (RB_ROOT.dataset.rbRepoStep === "1") rbAdvanceRepositoryStep();
return;
}
if (!rbValidateRepositoryFields(form)) {
event.preventDefault(); event.stopImmediatePropagation();
}
}, true);
form.addEventListener("reset", () => rbShowRepositoryIntro(false));
rbShowRepositoryIntro(false);
}
window.ResearchBee.showRepositoryIntro = rbShowRepositoryIntro;
window.ResearchBee.setRepositoryStep = rbSetRepositoryStep;
// ── Init ───────────────────────────────────────────────────────────────────
rbInitialiseAccessibility();
applyLanguage(getLanguage());
journalTab();
subjectTab();
licenseTab();
repositoryTab();
rbInitResetControls();
rbInitialiseRepositorySteps();
rbInitSharingChoices();
})();
</script>