/* Student Portal — Academy sign-in/sign-up + dashboard.
   Reuses main.css's design tokens (--accent-color, --heading-color, fonts)
   so these pages match the rest of the public site rather than inventing a
   separate visual language. Additional tokens below are local to this
   feature only. */

:root {
  --sp-border: #e2e8f0;
  --sp-muted: #64748b;
  --sp-bg-soft: #f8fafc;
  --sp-danger: #dc2626;
  --sp-success: #059669;
  --sp-sidebar-width: 300px;
  --sp-topbar-height: 68px;
}

:root[data-theme="dark"] {
  --sp-border: #27303B;
  --sp-muted: #94A3B8;
  --sp-bg-soft: #1B222C;
  --sp-danger: #F87171;
  --sp-success: #34D399;
}

/* ─── Shared ─────────────────────────────────── */
.student-auth-form .form-group,
.dash-project-form .form-group { margin-bottom: 18px; }

.student-auth-form label,
.dash-project-form label {
  display: block;
  font-family: Inter, sans-serif;
  font-weight: 600;
  font-size: .82rem;
  color: var(--heading-color);
  margin-bottom: 6px;
}

.form-hint { font-weight: 400; color: var(--sp-muted); }
.char-counter { display: block; text-align: right; font-size: .75rem; color: var(--sp-muted); margin-top: 4px; }
.char-counter.char-counter-over { color: var(--sp-danger); font-weight: 600; }

.student-auth-error, .form-error {
  background: rgba(220,38,38,.08);
  border: 1px solid var(--sp-danger);
  color: var(--sp-danger);
  border-radius: 8px;
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: .85rem;
  display: none;
}
.student-auth-error.visible, .form-error.visible { display: block; }

.student-auth-success {
  background: rgba(5,150,105,.08);
  border: 1px solid var(--sp-success);
  color: var(--sp-success);
  border-radius: 8px;
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: .85rem;
  display: none;
}
.student-auth-success.visible { display: block; }

/* !important is deliberate, not a shortcut -- this is a "hidden until JS
   says otherwise" utility applied to 50+ elements sitewide, several of
   which (e.g. .dash-view-image-link) have their own later-in-this-file
   display:block rule. Without !important, plain CSS source order decides
   the tie (same specificity, so whichever rule comes second wins) instead
   of "JS hasn't revealed this yet" -- which is how the blog hero image
   stayed visibly empty even with no image set, the bug that surfaced this. */
.d-none-init { display: none !important; }

/* ─── Auth page (academy/portal.html) ───────────── */
.student-auth-section {
  padding-top: 60px;
  padding-bottom: 90px;
  min-height: 70vh;
  display: flex;
  align-items: center;
}

.student-auth-card {
  max-width: 460px;
  margin: 0 auto;
  background: var(--surface-color);
  border: 1px solid var(--sp-border);
  border-radius: 20px;
  padding: 40px;
  box-shadow: 0 10px 40px rgba(15,23,42,0.06);
}

.student-auth-title {
  font-family: Nunito, sans-serif;
  font-weight: 800;
  font-size: 1.4rem;
  color: var(--heading-color);
  text-align: center;
  margin-bottom: 6px;
}
.student-auth-subtitle {
  text-align: center;
  color: var(--sp-muted);
  font-size: .88rem;
  margin-bottom: 28px;
}

.student-auth-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 28px;
  background: var(--sp-bg-soft);
  border-radius: 10px;
  padding: 4px;
}
.student-auth-tab {
  flex: 1;
  border: none;
  background: transparent;
  padding: 10px;
  border-radius: 8px;
  font-family: Inter, sans-serif;
  font-weight: 600;
  font-size: .9rem;
  color: var(--sp-muted);
  cursor: pointer;
  transition: all .2s;
}
.student-auth-tab.active {
  background: var(--surface-color);
  color: var(--accent-color);
  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}

.student-auth-subtabs {
  display: flex;
  gap: 20px;
  margin-bottom: 22px;
  border-bottom: 1px solid var(--sp-border);
}
.student-auth-subtab {
  border: none;
  background: none;
  padding: 8px 0;
  font-family: Inter, sans-serif;
  font-weight: 600;
  font-size: .85rem;
  color: var(--sp-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.student-auth-subtab.active { color: var(--accent-color); border-bottom-color: var(--accent-color); }

.form-row { display: flex; gap: 16px; }
.form-row .form-group { flex: 1; min-width: 0; }

.otp-input {
  letter-spacing: .5em;
  font-size: 1.2rem;
  text-align: center;
  font-weight: 700;
}

.btn-link-resend {
  display: block;
  width: 100%;
  text-align: center;
  background: none;
  border: none;
  color: var(--accent-color);
  font-family: Inter, sans-serif;
  font-weight: 600;
  font-size: .82rem;
  margin-top: 14px;
  cursor: pointer;
  padding: 6px;
}
.btn-link-resend:disabled { color: var(--sp-muted); cursor: not-allowed; }

.student-auth-switch {
  text-align: center;
  margin-top: 20px;
  font-size: .85rem;
  color: var(--sp-muted);
}
.student-auth-switch a { font-weight: 600; }

/* ─── Dashboard (academy/dashboard.html) ───────────── */
body.student-dashboard-page { background: var(--sp-bg-soft); }

#dashboard-root {
  display: none; /* toggled via inline style once auth is confirmed -- see student-portal.js */
  min-height: 100vh;
  flex-direction: column;
}

.dash-topbar {
  height: var(--sp-topbar-height);
  background: var(--surface-color);
  border-bottom: 1px solid var(--sp-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 28px;
  position: sticky;
  top: 0;
  z-index: 50;
}
/* Sizing/positioning comes from main.css's .logo-hanging-link/.logo-hanging-img
   (also used by partials/header.html) -- the uploaded logo file is a padded
   square with the actual wordmark occupying a small strip in the middle, so
   naive height-based sizing (what this used to do) rendered it as a barely-
   visible sliver. That pair of classes renders the image oversized and
   absolutely-positioned within a small overflow:visible box so only the
   wordmark itself appears at a normal size. .dash-logo only adds topbar-local
   vertical centering on top of that. */
.dash-logo { display: flex; align-items: center; }
.dash-topbar-right { display: flex; align-items: center; gap: 16px; }
.dash-user-name { font-family: Inter, sans-serif; font-weight: 600; font-size: .9rem; color: var(--heading-color); }

.dash-body { display: flex; flex: 1; }

.dash-sidebar {
  width: var(--sp-sidebar-width);
  flex-shrink: 0;
  background: var(--surface-color);
  border-right: 1px solid var(--sp-border);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.dash-new-btn { display: flex; align-items: center; justify-content: center; gap: 6px; }

.dash-kind-tabs { display: flex; background: var(--sp-bg-soft); border-radius: 10px; padding: 4px; gap: 4px; }
.dash-kind-tab {
  flex: 1; border: none; background: transparent; padding: 8px 6px; border-radius: 8px;
  font-family: Inter, sans-serif; font-weight: 600; font-size: .82rem; color: var(--sp-muted);
  cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 6px;
}
.dash-kind-tab.active { background: var(--surface-color); color: var(--accent-color); box-shadow: 0 1px 3px rgba(0,0,0,0.08); }

.dash-project-list { display: flex; flex-direction: column; gap: 6px; overflow-y: auto; }
.dash-project-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: 10px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background .15s, border-color .15s;
  background: none;
  text-align: left;
  width: 100%;
}
.dash-project-item:hover { background: var(--sp-bg-soft); }
.dash-project-item.active { background: rgba(37,99,235,.08); border-color: rgba(37,99,235,.25); }
.dash-project-item-thumb, .dash-project-item-thumb-placeholder {
  width: 40px; height: 40px; border-radius: 8px; object-fit: cover;
  background: var(--sp-bg-soft); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; color: var(--sp-muted);
}
/* The placeholder <i class="bi bi-folder2"> has no size of its own -- it
   was inheriting the page's normal text size (~1rem), rendering as a small
   glyph adrift in this 40px box instead of filling it. */
.dash-project-item-thumb-placeholder i { font-size: 1.35rem; }
.dash-project-item-name {
  font-family: Inter, sans-serif; font-weight: 600; font-size: .87rem; color: var(--heading-color);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* flex:1 + max-width without centering left this hugging the sidebar, with
   all the remaining space on wide screens sitting empty to the right --
   margin:auto centers it within that space instead. */
.dash-main { flex: 1; padding: 32px 40px; max-width: 960px; margin: 0 auto; }

.dash-empty-state { text-align: center; padding: 100px 20px; color: var(--sp-muted); }
.dash-empty-state i { font-size: 3rem; margin-bottom: 16px; display: block; }
.dash-empty-state h3 { font-family: Nunito, sans-serif; color: var(--heading-color); margin-bottom: 6px; }

.dash-view-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
.dash-view-header h2 { font-family: Nunito, sans-serif; font-weight: 800; font-size: 1.6rem; margin: 0; word-break: break-word; }
.dash-view-actions { display: flex; gap: 8px; flex-shrink: 0; }

.dash-view-image-link {
  display: block; position: relative; margin-bottom: 20px; border-radius: 14px;
  overflow: hidden; border: 1px solid var(--sp-border); background: var(--sp-bg-soft);
}
.dash-view-image {
  /* Cropped fill (not contain) reads better as a header image -- the
     clickable GLightbox link above still opens the full, uncropped image. */
  display: block; width: 100%; height: 340px; object-fit: cover;
}
.dash-view-image-link::after {
  content: "\f14d"; /* bootstrap-icons bi-arrows-fullscreen */
  font-family: bootstrap-icons; position: absolute; top: 12px; right: 12px;
  width: 32px; height: 32px; border-radius: 8px; background: rgba(15,23,42,.55);
  color: var(--contrast-color); display: flex; align-items: center; justify-content: center;
  font-size: .95rem; opacity: 0; transition: opacity .15s; pointer-events: none;
}
.dash-view-image-link:hover::after { opacity: 1; }
.dash-view-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.dash-view-tags .tag-badge {
  background: rgba(37,99,235,.08); color: var(--accent-color);
  font-family: Inter, sans-serif; font-weight: 600; font-size: .78rem;
  padding: 5px 12px; border-radius: 100px;
}
.dash-view-desc-blocks { margin-bottom: 20px; }
.dash-view-desc-blocks .dash-view-heading {
  font-family: Nunito, sans-serif; font-weight: 800; font-size: 1.2rem;
  color: var(--heading-color); margin: 18px 0 8px;
}
.dash-view-desc-blocks .dash-view-heading:first-child { margin-top: 0; }
.dash-view-desc-blocks .dash-view-desc { color: var(--default-color); line-height: 1.6; margin: 0 0 12px; white-space: pre-wrap; }
/* Styling for the "html" block type -- raw LLM-generated blog HTML (from
   the social media automation app) rendered as-is. That HTML leans on
   inline style="..." attributes for its colors/spacing, which this site's
   CSP (style-src with no 'unsafe-inline') silently drops everywhere, same
   as every other inline style on the site -- these tag-selector rules are
   the CSP-safe replacement, so the content still looks intentional instead
   of reverting to unstyled browser defaults. */
.dash-view-html-block { color: var(--default-color); line-height: 1.7; }
.dash-view-html-block h1:first-of-type { display: none; } /* already shown as the page title */
.dash-view-html-block h2 { font-family: Nunito, sans-serif; font-weight: 800; font-size: 1.5rem; color: var(--heading-color); margin: 1.75rem 0 0.85rem; padding-bottom: 0.4rem; border-bottom: 1px solid var(--sp-border); }
.dash-view-html-block h3 { font-family: Nunito, sans-serif; font-weight: 700; font-size: 1.15rem; color: var(--heading-color); margin: 1.4rem 0 0.6rem; }
.dash-view-html-block p { margin: 0 0 1.1rem; }
.dash-view-html-block ul, .dash-view-html-block ol { margin: 0 0 1.1rem; padding-left: 1.4rem; }
.dash-view-html-block li { margin-bottom: 0.4rem; }
.dash-view-html-block strong { color: var(--heading-color); }
.dash-view-html-block blockquote { border-left: 4px solid var(--accent-color); padding-left: 1.25rem; margin: 1.4rem 0; font-style: italic; color: var(--sp-muted); }
.dash-view-html-block table { border-collapse: collapse; width: 100%; margin: 1.25rem 0; }
.dash-view-html-block th, .dash-view-html-block td { border: 1px solid var(--sp-border); padding: 0.6rem 0.75rem; text-align: left; }
.dash-view-html-block th { background: var(--sp-bg-soft); font-weight: 700; }
.dash-view-html-block .cta-box { background: var(--sp-bg-soft); border: 1px solid var(--sp-border); border-left: 4px solid var(--accent-color); padding: 1.25rem 1.5rem; border-radius: 10px; margin-top: 1.75rem; }
.dash-view-html-block .cta-box h3 { margin-top: 0; }
.dash-view-html-block .cta-box a { display: inline-block; background: var(--accent-color); color: var(--contrast-color); padding: 0.55rem 1.1rem; font-weight: 600; text-decoration: none; border-radius: 6px; margin-top: 0.5rem; }
/* Admin-uploaded raw HTML files (blog-post-detail.js's html-raw block) --
   rendered in an iframe instead of this page's own DOM, so none of the
   .dash-view-html-block rules above apply to it on purpose; the uploaded
   file's own <style> renders unmodified. Height starts at a reasonable
   guess and gets corrected by JS once the iframe's real content loads. */
.dash-view-html-raw-frame { display: block; width: 100%; height: 600px; border: none; margin: 1rem 0; }
.dash-view-desc-img-link {
  display: block; margin: 4px 0 16px; border-radius: 12px; overflow: hidden;
  border: 1px solid var(--sp-border); background: var(--sp-bg-soft); position: relative;
}
.dash-view-desc-img { display: block; width: 100%; max-height: 320px; object-fit: contain; }
.dash-view-desc-img-link::after {
  content: "\f14d"; font-family: bootstrap-icons; position: absolute; top: 10px; right: 10px;
  width: 28px; height: 28px; border-radius: 8px; background: rgba(15,23,42,.55);
  color: var(--contrast-color); display: flex; align-items: center; justify-content: center;
  font-size: .85rem; opacity: 0; transition: opacity .15s; pointer-events: none;
}
.dash-view-desc-img-link:hover::after { opacity: 1; }
.dash-view-git { display: inline-flex; align-items: center; gap: 6px; font-family: Inter, sans-serif; font-weight: 600; color: var(--accent-color); }
.dash-view-status {
  display: inline-block; font-family: Inter, sans-serif; font-weight: 700; font-size: .72rem;
  text-transform: uppercase; letter-spacing: .03em; color: var(--sp-muted);
  background: var(--sp-bg-soft); border: 1px solid var(--sp-border);
  padding: 4px 10px; border-radius: 100px; margin-bottom: 16px;
}
.dash-view-status.status-pending { color: #b45309; background: rgba(217,119,6,.1); border-color: rgba(217,119,6,.3); }
.dash-view-status.status-approved { color: var(--sp-success); background: rgba(5,150,105,.1); border-color: rgba(5,150,105,.3); }
.dash-view-status.status-rejected { color: var(--sp-danger); background: rgba(220,38,38,.1); border-color: rgba(220,38,38,.3); }

.dash-img-upload { display: flex; align-items: center; gap: 16px; }
.dash-img-preview { width: 90px; height: 90px; border-radius: 12px; object-fit: cover; border: 1px solid var(--sp-border); }
.dash-file-label {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px dashed var(--sp-border); border-radius: 10px;
  padding: 10px 18px; font-family: Inter, sans-serif; font-weight: 600; font-size: .85rem;
  color: var(--accent-color); cursor: pointer;
}
.dash-file-input { display: none; }

/* ─── Description block editor ─────────────────────── */
.desc-blocks { display: flex; flex-direction: column; gap: 12px; margin-bottom: 12px; }
.desc-block {
  border: 1px solid var(--sp-border); border-radius: 12px; padding: 12px;
  background: var(--sp-bg-soft);
}
.desc-block-toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.desc-block-type-group { display: inline-flex; background: var(--surface-color); border: 1px solid var(--sp-border); border-radius: 8px; padding: 2px; }
.desc-block-type-btn {
  border: none; background: transparent; padding: 4px 12px; border-radius: 6px;
  font-family: Inter, sans-serif; font-weight: 600; font-size: .76rem;
  color: var(--sp-muted); cursor: pointer;
}
.desc-block-type-btn.active { background: var(--accent-color); color: var(--contrast-color); }
.desc-block-type-label {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: Inter, sans-serif; font-weight: 600; font-size: .78rem; color: var(--sp-muted);
}
.desc-block-remove-btn {
  margin-left: auto; border: none; background: transparent; color: var(--sp-danger);
  cursor: pointer; font-size: .95rem; padding: 4px 6px; line-height: 1; border-radius: 6px;
}
.desc-block-remove-btn:hover { background: rgba(220,38,38,.08); }
.desc-block-input {
  width: 100%; border: 1px solid var(--sp-border); border-radius: 8px;
  padding: 8px 12px; font-family: Roboto, sans-serif; font-size: .9rem; color: var(--default-color);
  background: var(--surface-color); resize: vertical;
}
.desc-block-input.is-heading { font-family: Nunito, sans-serif; font-weight: 800; font-size: 1.05rem; }
.desc-block-empty-hint { color: var(--sp-muted); font-size: .85rem; padding: 8px 0; }
.desc-add-btn { display: inline-flex; align-items: center; gap: 6px; }
.desc-add-buttons { display: flex; gap: 10px; flex-wrap: wrap; }

.dash-loading { text-align: center; padding: 100px 20px; color: var(--sp-muted); }

@media (max-width: 860px) {
  .dash-body { flex-direction: column; }
  .dash-sidebar { width: 100%; border-right: none; border-bottom: 1px solid var(--sp-border); max-height: 280px; }
  .dash-main { padding: 24px 20px; max-width: 100%; }
  .form-row { flex-direction: column; gap: 0; }
  /* .dash-view-image's fixed 340px height (see the rule above) assumes a
     desktop-width container, where 340px against an ~800-1200px-wide image
     stays close to the ~2.5:1 aspect ratio every AI-generated hero template
     actually is. On a mobile-width container that same fixed height forces
     object-fit:cover into a near-square crop window -- well over half the
     image gets cropped away from each side, which is wide enough to slice
     straight through the title text the hero generator composited across
     the template's full width. Switching to the template's own ratio here
     keeps the full width in frame at any container width, cropping only
     top/bottom (outside every template's safe zone) instead of the sides. */
  .dash-view-image { height: auto; aspect-ratio: 2.5 / 1; }
}

/* ─── academy/project.html — public single-project detail page ───────── */
/* !important because main.css's generic .container rule sets
   max-width:1280px!important -- without matching that, this narrower
   reading column silently loses the cascade and the page stretches to the
   full 1280px width instead of a comfortable reading measure. */
.project-detail-container { max-width: 820px !important; }
.project-detail-loading, .project-detail-notfound { text-align: center; padding: 60px 20px; color: var(--sp-muted); }
.project-detail-notfound .btn { margin-top: 16px; }
.project-detail-meta {
  font-family: Inter, sans-serif; font-weight: 600; font-size: .9rem;
  color: var(--sp-muted); margin-bottom: 12px;
}
.blog-detail-excerpt {
  font-family: Nunito, sans-serif; font-size: 1.1rem; font-weight: 600;
  color: var(--heading-color); line-height: 1.5; margin: 4px 0 20px;
}
