/* DataHub User Training — the entire visual identity lives here.
   Slides carry no inline styles; data-type drives all variation. */

:root {
  --dh-primary: #533fd1;      /* DataHub violet (alchemy primary.500) */
  --dh-ink: #374066;          /* alchemy gray.600 — primary text */
  --dh-muted: #5f6685;        /* alchemy gray.1700 — secondary text */
  --dh-faint: #8088a3;        /* alchemy gray.1800 — tertiary text / icons */
  --dh-bg: #ffffff;
  --dh-surface: #f9fafc;      /* alchemy gray.1500 — subtle surface */
  --dh-border: #ebecf0;       /* alchemy gray.100 — hairline borders */
  --dh-accent-bg: #f1f3fd;    /* alchemy violet.0 */
  --dh-warn: #c77100;         /* alchemy yellow.1000 */
  --dh-warn-bg: #fffaeb;      /* alchemy yellow.0 */
  --dh-good: #0d7543;         /* alchemy green.1000 */
  --dh-good-bg: #f1f8ee;      /* alchemy green.0 */
  --dh-tip: #09739a;          /* alchemy blue.1000 */
  --dh-tip-bg: #f1fbfe;       /* alchemy blue.0 */
  --dh-radius-sm: 4px;        /* alchemy radius.sm */
  --dh-radius-md: 8px;        /* alchemy radius.md */
  --dh-radius-lg: 12px;       /* alchemy radius.lg */
  --dh-shadow-sm: 0 2px 4px 0 rgba(33, 23, 95, 0.06); /* web-react shadowSm */
  --dh-font: "Mulish", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.reveal {
  font-family: var(--dh-font);
  font-size: 34px;
  color: var(--dh-ink);
}
.reveal-viewport { background: var(--dh-bg); }

.reveal section.slide { text-align: left; }
.reveal h2 {
  font-size: 1.25em;
  font-weight: 700;
  color: var(--dh-ink);
  margin-bottom: 0.6em;
  text-transform: none;
}

/* Two-column body/visual layout. ponytail: floats, because reveal.js sets
   an inline display style on the active section that defeats grid/flex. */
.slide .body { float: left; width: 52%; font-size: 0.75em; }
.slide .visual { float: right; width: 44%; font-size: 0.6em; }
.slide .body > p { margin: 0 0 0.7em; }  /* intro sentence before the list */
.slide .body ul { margin-left: 1em; }
.slide .body li { margin-bottom: 0.5em; }
.slide .visual img, .slide .visual svg { max-width: 100%; height: auto; }
/* Screenshots read as DataHub-style cards: hairline border, soft radius */
.slide .visual img {
  border: 1px solid var(--dh-border);
  border-radius: var(--dh-radius-md);
  box-shadow: var(--dh-shadow-sm);
}

/* Slides that opted out of a visual: body spans the full width */
section[data-visual="none"] .body { float: none; width: 100%; }

/* Narration: the virtual presenter's voice-over text. Three modes:
   - presenter mode (human narrates): hidden, silent.
   - narrator sound ON: hidden as a block — SPOKEN instead (no
     on-screen duplicate; readers use sound-off mode).
   - sound OFF (default): the slide's opening step — title + narration
     shown first, one advance reveals the content (reveal fragments
     injected by nav.js), and the narration then steps aside.
   Flows into the static exports either way, unlike speaker notes. */
.slide .narration {
  clear: both;
  width: 82%;
  margin: 0.8em auto 0;
  padding: 0.7em 1em;
  background: var(--dh-surface);
  border-left: 3px solid var(--dh-primary);
  border-radius: var(--dh-radius-sm);
  color: var(--dh-ink);
  font-size: 0.62em;
  line-height: 1.55;
  text-align: left;
}
body.dh-presenter-mode .slide .narration,
body.dh-narrator-on .slide .narration { display: none; }
/* virtual presenter disabled: plain slides, narration as an inline
   block, and no narrator sound button */
body.dh-vp-off .slide .narration { display: block; }
body.dh-vp-off .dh-sound-button { display: none; }
body.dh-presenter-mode.dh-vp-off .slide .narration { display: none; }
/* the spoken color intro (data-intro) doubles as a displayed lead-in
   line whenever the narration block itself is displayed — readers get
   the same cue listeners hear */
.slide .narration[data-intro]::before {
  content: attr(data-intro);
  display: block;
  font-weight: 700;
  color: var(--dh-primary);
  margin-bottom: 0.3em;
}
/* deixis variants inside narration: <span class="spoken"> is for the
   narrator's voice only ("this slide" — said over the visible slide);
   <span class="read"> is for displayed text only ("the next slide" —
   read before the content appears). narrate.py keeps spoken and drops
   read; every displayed/exported form does the reverse. */
.narration .spoken { display: none; }
/* Narration intro step: while the content fragments are still hidden,
   the narration IS the slide. Reveal's hidden fragments keep their
   layout space (visibility-hidden), which would shove the narration to
   the bottom — drop them from layout, center the narration in the
   slide, size it to read from the back of the room, and set it on a
   dialog balloon for a high-contrast surface. */
.slide:has(.fragment:not(.visible)) > .fragment:not(.visible) {
  display: none;
}
.slide:has(.fragment:not(.visible)) .narration {
  position: relative;
  width: 84%;
  margin: 1em auto 40px;      /* bottom room for the balloon tail */
  padding: 1em 1.3em;
  font-size: 0.8em;
  line-height: 1.55;
  text-align: left;
  color: var(--dh-ink);
  background: var(--dh-bg);
  border: 2px solid var(--dh-primary);
  border-radius: 20px;
  box-shadow: 0 14px 44px rgba(33, 23, 95, 0.14);
}
/* The balloon's tail (::before is taken by the data-intro lead-in).
   It OVERLAPS the balloon's bottom edge: the white fill erases the
   border segment behind it, and only the two side curves are stroked
   (no stroke on the top edge), so tail and balloon read as one shape. */
.slide:has(.fragment:not(.visible)) .narration::after {
  content: "";
  position: absolute;
  left: 11%;
  bottom: -30px;
  width: 48px;
  height: 34px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 34'%3E%3Cpath d='M8 0 C10 14 20 26 44 31 C28 28 24 14 26 0 Z' fill='%23ffffff'/%3E%3Cpath d='M8 0 C10 14 20 26 44 31 C28 28 24 14 26 0' fill='none' stroke='%23533fd1' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E")
    no-repeat center / contain;
}
/* once the content step is revealed, the narration steps aside */
.slide:has(.body.fragment.visible) .narration,
.slide:has(.visual.fragment.visible) .narration { display: none; }

/* Story slides: two side-by-side narrative columns spanning the full
   width, with a slim full-width visual strip beneath. */
.slide .body.body-cols {
  float: none; width: 100%; font-size: 0.7em;
  display: grid; grid-template-columns: 1fr 1fr; gap: 1em;
}
.body-cols .story-col { background: var(--dh-surface); border: 1px solid var(--dh-border); border-radius: var(--dh-radius-md); padding: 0.7em 1em; }
.body-cols .story-col h3 { margin: 0 0 0.4em; font-size: 1em; color: var(--dh-primary); }
.body-cols .story-col p { margin: 0 0 0.5em; }
.slide .visual.visual-strip { float: none; width: 100%; font-size: 0.6em; margin-top: 0.4em; }

/* Full-width variants: title, objectives, summary, quiz center on content */
.reveal section.slide[data-type="title"] { text-align: center; }
/* Persistent DataHub logo in the deck's fixed chrome layer (same layer as
   .dh-menu-button — unscaled, present on every slide including overview
   mode). Pure CSS on the viewport, so no slide markup changes. z-index 20:
   above slide content, below the menu button (30), resume modal (50) and
   reveal's lightbox overlay (100+). */
.reveal-viewport::after {
  content: "";
  position: fixed;
  top: 14px;
  left: 18px;
  width: 26px;
  height: 26px;
  z-index: 20;
  pointer-events: none;
  /* mark only — the full wordmark (with its Cloud badge) lives on title
     slides; the corner stays minimal on content slides */
  background-image: url("datahub-mark.svg");
  background-repeat: no-repeat;
  background-size: auto 26px;
  background-position: left center;
  opacity: 0.85;
}
/* Official DataHub logo on title slides only — pure CSS so slide markup
   stays untouched. Mark + wordmark are drawn as two centered background
   images on one pseudo-element; url() resolves relative to this file. */
.reveal section.slide[data-type="title"]::before {
  content: "";
  display: block;
  height: 44px;
  margin: 0 auto 0.8em;
  background-image: url("datahub-mark.svg"), url("datahub-logo.svg");
  background-repeat: no-repeat, no-repeat;
  background-size: auto 40px, auto 28px;
  background-position: calc(50% - 74px) center, calc(50% + 26px) center;
}
.reveal section.slide[data-type="title"] h2 { font-size: 1.8em; color: var(--dh-primary); }
.reveal section.slide[data-type="title"] .body,
.reveal section.slide[data-type="title"] .visual { float: none; width: 100%; }

/* Callout banners — the label comes from CSS, never from slide text */
section[data-type^="callout-"] h2::before {
  display: block;
  font-size: 0.5em;
  font-weight: 800;
  letter-spacing: 0.12em;
}
section[data-type="callout-watchout"] h2::before { content: "⚠ WATCH OUT"; color: var(--dh-warn); }
section[data-type="callout-protip"] h2::before { content: "★ PRO TIP"; color: var(--dh-tip); }
section[data-type="callout-bestpractice"] h2::before { content: "✔ BEST PRACTICE"; color: var(--dh-good); }
section[data-type="callout-watchout"] { background: var(--dh-warn-bg); }
section[data-type="callout-protip"] { background: var(--dh-tip-bg); }
section[data-type="callout-bestpractice"] { background: var(--dh-good-bg); }
section[data-type^="callout-"] { border-radius: var(--dh-radius-lg); padding: 0.8em 1em; }

/* Labs and quizzes get a left accent bar */
section[data-type="lab"], section[data-type="quiz"] {
  border-left: 6px solid var(--dh-primary);
  padding-left: 0.8em;
  background: var(--dh-accent-bg);
  border-radius: 0 var(--dh-radius-lg) var(--dh-radius-lg) 0;
}
section[data-type="lab"] h2::before {
  display: block; font-size: 0.5em; font-weight: 800;
  letter-spacing: 0.12em; color: var(--dh-primary);
  content: "🧪 LAB";
}

/* Exam slides: interactive multiple-choice, JS-rendered by assets/exam.js.
   The widget IS the visual slot and spans the full width. */
section[data-type="exam"] {
  border-left: 6px solid var(--dh-primary);
  padding-left: 0.8em;
  background: var(--dh-accent-bg);
  border-radius: 0 var(--dh-radius-lg) var(--dh-radius-lg) 0;
}
section[data-type="exam"] h2::before {
  display: block; font-size: 0.5em; font-weight: 800;
  letter-spacing: 0.12em; color: var(--dh-primary);
  content: "📝 QUICK EXAM";
}
section[data-type="exam"] .visual { float: none; width: 100%; font-size: 0.7em; }
.exam-widget .exam-progress { color: var(--dh-muted); font-size: 0.8em; margin-bottom: 0.4em; }
.exam-widget .exam-question { font-weight: 600; margin-bottom: 0.6em; }
.exam-widget .exam-choice {
  display: block; width: 100%; text-align: left;
  font: inherit; color: var(--dh-ink);
  background: var(--dh-bg);
  border: 1px solid var(--dh-border);
  border-radius: var(--dh-radius-md);
  padding: 0.35em 0.6em;
  margin-bottom: 0.35em;
  cursor: pointer;
}
.exam-widget .exam-choice:hover:enabled { border-color: var(--dh-primary); }
.exam-widget .exam-choice:disabled { cursor: default; }
.exam-widget .exam-choice.exam-correct { border-color: var(--dh-good); background: var(--dh-good-bg); }
.exam-widget .exam-choice.exam-wrong { border-color: var(--dh-warn); background: var(--dh-warn-bg); }
.exam-widget .exam-feedback { margin: 0.4em 0; font-weight: 600; }
.exam-widget .exam-feedback.exam-right { color: var(--dh-good); }
.exam-widget .exam-feedback.exam-missed { color: var(--dh-warn); }
.exam-widget .exam-start, .exam-widget .exam-next {
  font: inherit; font-weight: 600;
  color: var(--dh-bg);
  background: var(--dh-primary);
  border: none;
  border-radius: var(--dh-radius-md);
  padding: 0.35em 1em;
  cursor: pointer;
}
.exam-widget .exam-back {
  font: inherit; font-weight: 600;
  color: var(--dh-primary);
  background: var(--dh-bg);
  border: 1px solid var(--dh-primary);
  border-radius: var(--dh-radius-md);
  padding: 0.35em 1em;
  margin-left: 0.5em;
  cursor: pointer;
}
.exam-widget .exam-nav {
  display: block;
  font: inherit; font-weight: 600;
  color: var(--dh-primary);
  background: var(--dh-bg);
  border: 1px solid var(--dh-primary);
  border-radius: var(--dh-radius-md);
  padding: 0.35em 1em;
  margin-top: 0.4em;
  cursor: pointer;
}
.exam-widget .exam-nav:hover { background: var(--dh-accent-bg); }

/* Deck chrome icon buttons, docked beside reveal's slide arrows
   (bottom-right): return-to-menu and narrator sound. Fixed pixel sizing
   on purpose: reveal's controls are unscaled chrome, and these buttons
   sit in that layer, not on the slide. */
.dh-menu-button,
.dh-sound-button {
  position: fixed;
  bottom: 18px;
  z-index: 30;
  width: 42px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--dh-font);
  color: var(--dh-primary);
  background: var(--dh-bg);
  border: 1px solid var(--dh-border);
  border-radius: var(--dh-radius-md);
  box-shadow: var(--dh-shadow-sm);
  padding: 0;
  cursor: pointer;
  opacity: 0.75;
}
.dh-menu-button { right: 110px; }
.dh-sound-button { right: 158px; }
.dh-menu-button:hover,
.dh-sound-button:hover { opacity: 1; background: var(--dh-accent-bg); border-color: var(--dh-primary); }
.dh-menu-button svg,
.dh-sound-button svg { width: 20px; height: 20px; display: block; stroke: currentColor; }
/* speaker icon states: waves when narrating, slash when off */
.dh-sound-button .dh-wave { display: none; }
.dh-sound-button.dh-on .dh-wave { display: initial; }
.dh-sound-button.dh-on .dh-slash { display: none; }

/* Resume-or-restart modal shown on re-entering a deck. Full-screen
   backdrop blocks the deck until one of the two options is chosen. */
.dh-resume-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(55, 64, 102, 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
}
.dh-resume {
  background: var(--dh-bg);
  border: 1px solid var(--dh-border);
  border-radius: var(--dh-radius-lg);
  padding: 40px 48px;
  max-width: 34em;
  box-shadow: 0 8px 24px rgba(33, 23, 95, 0.16);
  font-family: var(--dh-font);
  font-size: 20px;
  color: var(--dh-ink);
  text-align: center;
}
.dh-resume-msg { margin: 0 0 24px; font-weight: 700; }
.dh-resume-go, .dh-resume-restart {
  display: block;
  width: 100%;
  font: inherit;
  font-weight: 600;
  border-radius: var(--dh-radius-md);
  padding: 12px 20px;
  cursor: pointer;
  margin: 10px 0 0;
}
.dh-resume-go {
  color: var(--dh-bg);
  background: var(--dh-primary);
  border: 1px solid var(--dh-primary);
}
.dh-resume-restart {
  color: var(--dh-primary);
  background: var(--dh-bg);
  border: 1px solid var(--dh-primary);
}
.dh-resume-restart:hover { background: var(--dh-accent-bg); }

/* The visual backlog, visible in draft presentations on purpose */
.visual-todo {
  border: 2px dashed var(--dh-warn);
  background: var(--dh-warn-bg);
  color: var(--dh-warn);
  padding: 1em;
  font-size: 0.55em;
  border-radius: var(--dh-radius-md);
}
.visual-todo::before { content: "VISUAL TODO — "; font-weight: 800; }

.reveal code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  background: var(--dh-accent-bg);
  padding: 0.05em 0.3em;
  border-radius: var(--dh-radius-sm);
  font-size: 0.9em;
  overflow-wrap: anywhere; /* long unbroken URNs must wrap, not spill the column */
}
.reveal pre code { display: block; padding: 0.7em; overflow-x: auto; }


/* On-the-spot certificate: shown full screen the moment it is earned */
.dh-cert-backdrop {
  position: fixed;
  inset: 0;
  z-index: 55;
  background: rgba(55, 64, 102, 0.65);
  display: flex;
  align-items: center;
  justify-content: center;
}
.dh-cert-modal {
  background: var(--dh-bg);
  border: 6px double var(--dh-good);
  border-radius: 16px;
  padding: 40px 56px;
  max-width: 34em;
  text-align: center;
  font-family: var(--dh-font);
  color: var(--dh-ink);
  box-shadow: 0 12px 48px rgba(55, 64, 102, 0.4);
}
.dh-cert-seal { font-size: 52px; }
.dh-cert-modal h2 { font-size: 26px; color: var(--dh-good); margin: 8px 0; }
.dh-cert-name { font-size: 20px; font-weight: 700; margin: 4px 0; }
.dh-cert-when { color: var(--dh-muted); font-size: 15px; margin: 0 0 18px; }
.dh-cert-open {
  display: inline-block; margin-right: 10px;
  color: var(--dh-good); font-weight: 700; font-size: 15px;
}
.dh-cert-close {
  font: inherit; font-size: 15px; font-weight: 600;
  color: var(--dh-bg); background: var(--dh-good);
  border: none; border-radius: 8px; padding: 8px 18px; cursor: pointer;
}

/* End-of-module curriculum contribution rows on the exam widget */
.exam-widget .exam-curricula { margin-top: 0.8em; }
.exam-widget .exam-curriculum-row { margin-bottom: 0.45em; }
.exam-widget .exam-curriculum-label {
  display: block; font-size: 0.75em; color: var(--dh-muted); margin-bottom: 0.15em;
}
.exam-widget .exam-curriculum-bar {
  background: #e5e2f8; border-radius: 6px; height: 0.45em;
  overflow: hidden; max-width: 24em;
}
.exam-widget .exam-curriculum-fill { background: var(--dh-primary); height: 100%; width: 0; }

/* Certification-code flow inside the on-earn certificate modal */
.dh-cert-modal .dh-code-btn {
  font: inherit; font-size: 14px; font-weight: 600;
  color: var(--dh-bg); background: var(--dh-good);
  border: none; border-radius: 8px; padding: 7px 14px;
  cursor: pointer; margin: 10px 4px 0;
}
.dh-cert-modal .dh-code-input {
  display: block; width: 70%; margin: 8px auto 0;
  font: inherit; font-size: 14px; color: var(--dh-ink);
  border: 1px solid var(--dh-border); border-radius: 8px; padding: 6px 10px;
}
.dh-cert-modal .dh-code-bundle {
  display: block; width: 100%; height: 64px; margin-top: 10px;
  font-family: ui-monospace, Menlo, monospace; font-size: 11px;
  word-break: break-all; border: 1px solid var(--dh-border);
  border-radius: 8px; padding: 6px;
}
.dh-cert-modal .dh-code-out { color: var(--dh-muted); font-size: 13px; margin: 8px 0 0; }

/* Add-to-LinkedIn badge on the on-earn certificate modal */
.dh-cert-modal .dh-li-badge {
  display: inline-block; font-size: 14px; font-weight: 700;
  color: #ffffff; background: #0a66c2; border-radius: 8px;
  padding: 7px 14px; text-decoration: none; margin: 10px 4px 0;
}

/* Details line under the Add-to-LinkedIn badge on the on-earn modal */
.dh-cert-modal .dh-skills-label { color: var(--dh-muted); font-size: 13px; margin: 10px 0 4px; }
