/* styles.css — extracted from parts/00_head.html.
 * Single external stylesheet for www.lizibuilds.tech. Moved out of an inline
 * <style> block so the raw HTML document is mostly content, not markup/CSS
 * (agent-readiness: higher text-to-markup ratio). Behavior/visuals unchanged —
 * this is the same CSS, just loaded via <link rel="stylesheet"> instead of inlined.
 * Edit this file directly (there is no build step for it); if you touch
 * parts/00_head.html's <link> tag, keep the href in sync. */

    /* CSS Custom Properties (:root) */
    :root {
      --bg-main: #FAFAFA;
      --bg-surface: #FFFFFF;
      --text-primary: #0F172A;
      --text-secondary: #475569;
      --text-muted: #64748B;
      --border-color: #E2E8F0;
      --accent-primary: #8B7EE8;
      --accent-hover: #7A6BE0;
      --accent-subtle: #F0EDFB;
      --accent-secondary: #16A34A;
      --font-primary: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
      --font-mono: "JetBrains Mono", "Fira Code", "Courier New", monospace;
    }

    /* Global Viewport & Reset Rules */
    *, *::before, *::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    html {
      scroll-behavior: smooth;
      -webkit-text-size-adjust: 100%;
      -moz-text-size-adjust: 100%;
      text-size-adjust: 100%;
    }

    body {
      background-color: var(--bg-main);
      color: var(--text-primary);
      font-family: var(--font-primary);
      font-size: 16px;
      line-height: 1.5;
    }

    /* Primary Layout Wrapper */
    .portfolio-container {
      max-width: 100%;
      margin-left: auto;
      margin-right: auto;
      width: 100%;
      padding: 7px 15px 15px 15px;
    }

    /* Bold letter contrast for filter buttons */
    .filter-btn b {
      font-weight: 800;
    }

    /* Carousel & Scroll Stability */
    .projects-carousel, .events-carousel, .value-carousel {
      display: flex;
      flex-direction: row;
      justify-content: flex-start;
      gap: 12px;
      overflow-x: auto;
      overflow-anchor: none;
      scroll-snap-type: x mandatory;
      scrollbar-width: none;
      -ms-overflow-style: none;
    }
    .projects-carousel::-webkit-scrollbar,
    .events-carousel::-webkit-scrollbar,
    .value-carousel::-webkit-scrollbar {
      display: none;
    }

    .project-card, .event-card {
      width: calc(100% - 22px);
      min-width: calc(100% - 22px);
      max-width: calc(100% - 22px);
      scroll-snap-align: start;
      flex-shrink: 0;
      flex-grow: 0;
      overflow-anchor: none;
    }
    .value-card {
      width: calc(100% - 20px);
      min-width: calc(100% - 20px);
      max-width: calc(100% - 20px);
      scroll-snap-align: start;
      flex-shrink: 0;
      flex-grow: 0;
      overflow-anchor: none;
    }

    .projects-carousel {
      margin: 0 -15px 4px -15px;
      padding: 0 15px;
      scroll-padding-left: 15px;
    }
    .events-carousel {
      margin: 0 -15px 4px -15px;
      padding: 0 15px;
      scroll-padding-left: 15px;
    }
    .value-carousel {
      margin: 4px -15px;
      padding: 0 15px;
      scroll-padding-left: 15px;
    }

    /* Profile Card Styling */
    .profile-card {
      background: var(--bg-surface);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      padding: 15px;
      margin-bottom: 24px;
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.05);
    }

    /* Projects, Skills, Events, Value, Contact, Help Yourself Containers */
    .projects-card-container,
    .skills-card,
    .events-card-container,
    .value-card-container,
    .contact-card-container,
    .help-yourself-card-container {
      background: var(--bg-surface);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      padding: 15px;
      margin-bottom: 24px;
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.05);
    }
    /* Value section covers at least half the screen on every device.
       margin-bottom stays 24px (from the shared rule) so the gap down to the
       Contact section matches the spacing between all other sections. */
    .value-card-container {
      min-height: 50vh;
      display: flex;
      flex-direction: column;
    }
    .value-card-container .value-carousel {
      flex: 1 1 auto;
      align-items: stretch;
    }
    .value-card-container .value-card {
      height: auto !important;
      min-height: 251px;
    }

    /* Contact section: compact. Height is only whatever the title + one row of
       buttons needs (no min-height, no vertical centering). As the last section
       before the footer it keeps the 12px bottom margin the value section used to
       carry, so the footer clearance stays exactly as it was. The extra bottom
       padding (15px base + 48px) makes the space below the last button (63px)
       mirror the space above the title (card edge -> first button = 63px), so the
       buttons read as vertically balanced inside the card. */
    .contact-card-container {
      margin-bottom: 12px;
      padding-bottom: 25px;
    }
    .contact-buttons-row {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 12px;
      width: 100%;
    }
    .contact-btn {
      width: 80%;
      max-width: 300px;
      min-width: 0;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      height: 48px;
      padding: 0 10px;
      background: var(--bg-surface);
      color: var(--text-primary);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      font-family: var(--font-primary);
      font-size: 15px;
      font-weight: 700;
      letter-spacing: 0.01em;
      text-decoration: none;
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.05);
      transition: background 0.15s ease, border-color 0.15s ease;
      -webkit-tap-highlight-color: transparent;
    }
    .contact-btn:hover {
      background: var(--accent-subtle);
      border-color: var(--accent-primary);
    }
    .contact-btn svg {
      width: 21px;
      height: 21px;
      flex-shrink: 0;
      color: var(--accent-primary);
    }
    .contact-btn span {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    /* Narrow phones: trim gap/padding/font a touch so icon + label never crowd */
    @media (max-width: 380px) {
      .contact-btn {
        font-size: 14px;
        gap: 6px;
        padding: 0 8px;
      }
      .contact-btn svg { width: 20px; height: 20px; }
    }
    /* Desktop: keep the same centered, capped width */
    @media (min-width: 1024px) {
      .contact-btn { height: 52px; font-size: 16px; }
    }

    .skills-card {
      padding: 16px;
    }

    .section-title {
      font-family: var(--font-primary);
      font-size: 22px;
      font-weight: 700;
      color: var(--text-primary);
      text-align: center;
      margin-top: 0;
      margin-bottom: 16px;
      letter-spacing: 0.05em;
    }

    /* Sticky Header & Footer Styles */
    .sticky-header {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 44px;
      min-height: 44px;
      z-index: 100;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0px 19.5px 0px 15px;
      box-sizing: border-box;
      border-bottom: 1px solid rgba(226, 232, 240, 0.8);
      background: rgba(255, 255, 255, 0.85);
      backdrop-filter: blur(8px);
      -webkit-backdrop-filter: blur(8px);
      opacity: 0;
      transform: translateY(-100%);
      pointer-events: none;
      transition: opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
    }
    .sticky-header.visible {
      opacity: 1;
      transform: translateY(0);
      pointer-events: auto;
    }

    .sticky-footer {
      position: fixed;
      bottom: 0;
      left: 0;
      width: 100%;
      height: 44px;
      min-height: 44px;
      z-index: 90;
      background: rgba(255, 255, 255, 0.90);
      backdrop-filter: blur(8px);
      -webkit-backdrop-filter: blur(8px);
      border-top: 1px solid var(--border-color);
      padding: 4px 15px;
      display: flex;
      align-items: center;
      justify-content: center;
      box-sizing: border-box;
      opacity: 1;
      transform: translateY(0);
      transition: opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
    }
    .sticky-footer.hidden {
      opacity: 0;
      transform: translateY(100%);
      pointer-events: none;
    }

    /* Status Pulse Animation */
    .status-pulse-dot {
      width: 8px;
      height: 8px;
      border-radius: 50%;
      background: #22C55E;
      position: relative;
      flex-shrink: 0;
      animation: status-pulse 2s infinite;
    }
    @keyframes status-pulse {
      0% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.7); }
      70% { box-shadow: 0 0 0 6px rgba(34, 197, 94, 0); }
      100% { box-shadow: 0 0 0 0 rgba(34, 197, 94, 0); }
    }

    /* File Select Box Fallback — !important is required because the label carries inline background/border/color that would otherwise win over this rule */
    .file-select-box:has(.file-checkbox:checked),
    .file-select-box.selected {
      background: var(--accent-subtle) !important;
      border: 1.5px solid var(--accent-primary) !important;
      color: var(--accent-primary) !important;
    }

    /* Card sub-tab alignment: both tabs share identical geometry so top/bottom edges line up; only the active tab's bottom edge dissolves into the content box */
    .subtab-btn, .event-subtab-btn {
      padding: 6px 12px;
      line-height: 1;
      border: 1px solid var(--border-color);
      border-radius: 6px 6px 0 0;
      position: relative;
      bottom: -1px;
      box-sizing: border-box;
    }
    /* Project sub-tabs: all caps (match events) */
    .subtab-btn {
      text-transform: uppercase;
    }
    /* Event sub-tabs: all caps */
    .event-subtab-btn {
      text-transform: uppercase;
    }

    /* Skillset inactive tints: light lavender = technical, light amber = business/finance */
    .skill-tab:not(.active) {
      background: #F3F1FC !important;
      border: 1px solid #E4DEF7 !important;
    }
    .skill-tab.business-tab:not(.active) {
      background: #EEF9F1 !important;
      border: 1px solid #D6EFDD !important;
    }

    /* Forced line break: used only by the events filter bar (fewer, shorter tabs) */
    .tab-row-break {
      flex-basis: 100%;
      width: 100%;
      height: 0;
      margin: 0;
      padding: 0;
    }
    /* Skillset rows: tabs wrap naturally (browser packs each row as full as it can fit);
       row-gap gives the ~7px vertical spacing since there's no manual break div here */
    .skillset-tabs-grid { column-gap: 8px !important; row-gap: 7px !important; }
    /* Events filter rows: match skillset vertical gap exactly (7px).
       row-gap does the spacing; the break div only forces the wrap (height 0). */
    /* Events filter rows: force 3+2 via the break div, but the break sits on its own
       wrapped line so row-gap would apply on BOTH sides of it (7+7=14). Pull it up by
       one row-gap so the visible rows are separated by exactly one 7px gap. */
    .events-filter-bar { column-gap: 8px !important; row-gap: 0 !important; }
    .events-filter-bar .tab-row-break { height: 7px; margin-top: 0; }

    /* Phones: tighten tab padding/gap/font so more tabs fit per row — denser, better-
       filled centered rows, and narrower devices like Galaxy S20 keep up with wider ones */
    @media (max-width: 767px) {
      .skill-tab, .event-filter-btn {
        padding: 0 7px !important;
        font-size: 11.5px !important;
      }
      .skillset-tabs-grid {
        column-gap: 5px !important;
      }
      .events-filter-bar {
        column-gap: 6px !important;
      }
    }

    /* Mobile/tablet: center tab rows */
    @media (max-width: 1023px) {
      .skillset-tabs-grid, .events-filter-bar {
        justify-content: center !important;
      }
    }
    /* Narrow phones (e.g. Galaxy S20 at 360px): tighten tab padding/gap/font so more
       tabs fit per row, closing the gap with wider phones like standard iPhones */
    @media (max-width: 380px) {
      .skill-tab, .event-filter-btn {
        padding: 0 7px !important;
        font-size: 11.5px !important;
      }
      .skillset-tabs-grid {
        column-gap: 5px !important;
      }
      .events-filter-bar {
        column-gap: 6px !important;
      }
    }

    /* Card URL tag: small blue mono tag on the right edge of the title line */
    .card-url-tag {
      font-family: var(--font-mono);
      font-size: 11px;
      font-weight: 600;
      color: var(--accent-primary);
      text-transform: uppercase;
      letter-spacing: 0.05em;
      flex-shrink: 0;
      text-decoration: none;
      margin-left: auto;
    }
    .card-url-tag:hover {
      color: var(--accent-hover);
    }
    /* Reveal fade-in: applied to content that becomes visible via a tab switch
       or by scrolling a hidden card into view. ~0.5s so transitions feel smooth.
       Anything already on screen never gets this class, so it stays instant. */
    @keyframes revealFade {
      0%   { opacity: 0; transform: translateY(4px); }
      100% { opacity: 1; transform: translateY(0); }
    }
    .reveal-fade {
      animation: revealFade 0.5s ease both;
    }

    /* Section reveal (vertical scroll): a visible but smooth fade-in. No vertical
       movement (that felt like loading); just opacity from 0 to 1 over ~0.6s with
       a soft ease. The JS triggers it slightly before the section is fully in view
       so it reads as smooth, not abrupt. */
    @keyframes sectionReveal {
      0%   { opacity: 0; }
      100% { opacity: 1; }
    }
    .section-reveal {
      animation: sectionReveal 0.6s ease-out both;
    }

    /* Lazy-load shimmer placeholder for the 2nd card's media */
    @keyframes lazyShimmer {
      0% { background-position: -200% 0; }
      100% { background-position: 200% 0; }
    }
    .lazy-media {
      opacity: 0;
      transition: opacity 0.2s ease;
    }
    .lazy-media.lazy-loaded {
      opacity: 1;
    }
    /* Video thumbnails: first frame shows via #t fragment; no black box */
    video.lazy-media {
      background: transparent;
    }
    /* Crop in slightly to hide the light border baked into the source video clips —
       wrapper already clips overflow, so this just zooms past the visible edge */
    .project-video {
      transform: scale(1.12);
      transform-origin: center center;
    }
    /* Video thumbnail poster keeps its dimmed look after lazy load */
    .media-video-thumb .lazy-media.lazy-loaded {
      opacity: 0.75;
    }
    .lazy-shimmer {
      position: absolute;
      inset: 0;
      background: linear-gradient(90deg, #E2E8F0 25%, #F1F5F9 50%, #E2E8F0 75%);
      background-size: 200% 100%;
      animation: lazyShimmer 1.4s ease-in-out infinite;
      z-index: 1;
    }
    .lazy-shimmer.lazy-hide {
      opacity: 0;
      transition: opacity 0.4s ease;
      pointer-events: none;
    }
    /* Tech Stack: always a single flowing paragraph — never columns/tabs/grid.
       Tool names stay highlighted in blue; body text stays gray. */
    .pane-techstack {
      column-count: 1 !important;
      columns: auto !important;
      grid-template-columns: none !important;
      display: block;
    }
    /* Events media: uniform 3x3 grid that fills the fixed pane exactly.
       Every cell is an equal slot; media fills via object-fit: cover (clips
       overflow). No scrolling. Native size only shows in the lightbox popup. */
    .media-grid {
      display: grid !important;
      grid-template-columns: repeat(3, 1fr) !important;
      grid-template-rows: repeat(3, 1fr) !important;
      grid-auto-rows: 1fr !important;
      gap: 6px !important;
      width: 100%;
      height: 100%;
    }
    .media-grid > .media-thumb,
    .media-grid > .media-grid-img {
      width: 100%;
      height: 100%;
      min-width: 0;
      min-height: 0;
      object-fit: cover;
    }
    .media-grid > .media-thumb > .media-grid-img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
    /* Media pane: fixed, no scrolling */
    .event-pane-media {
      overflow: hidden !important;
    }
    /* Disabled URL tag: gray + unclickable, used on hardware/HW+SW cards where there's nothing to open */
    .card-url-tag.card-url-disabled,
    .card-url-tag.card-url-disabled:hover {
      color: var(--text-muted);
      pointer-events: none;
      cursor: default;
    }

    /* Profile action icons: stay 22.5px normally; only shrink a hair on the very narrowest viewports so all 5 fit */
    .profile-actions .action-btn { flex-shrink: 0; display: flex; align-items: center; }
    .profile-actions .action-btn svg {
      width: clamp(19px, 6vw, 22.5px) !important;
      height: clamp(19px, 6vw, 22.5px) !important;
    }

    /* Desktop Media Queries (>= 1024px) */
    @media (min-width: 768px) and (max-width: 1023px) {
      .portfolio-container {
        max-width: 700px;
        margin-left: auto;
        margin-right: auto;
        width: 100%;
        padding: 7px 15px 15px 15px;
      }
    }

    @media (min-width: 1024px) {
      .portfolio-container {
        max-width: 1320px;
        margin-left: auto;
        margin-right: auto;
        width: 100%;
        padding: 16px 32px 32px 32px;
      }
      .sticky-header, .sticky-footer {
        left: 50%;
        transform: translateX(-50%);
        max-width: 1320px;
        width: 100%;
      }
      .sticky-header.visible {
        transform: translateX(-50%) translateY(0);
      }
      .sticky-footer {
        transform: translateX(-50%) translateY(0);
      }
      .sticky-footer.hidden {
        transform: translateX(-50%) translateY(100%);
      }
      
      /* Desktop: keep Projects/Events/Value as horizontal sliders — sized so 3 cards show fully and a 4th peeks at the edge */
      .projects-carousel, .events-carousel, .value-carousel {
        display: flex !important;
        overflow-x: auto !important;
        scroll-snap-type: x mandatory;
        margin: 0 0 4px 0 !important;
        padding: 0 !important;
        scroll-padding-left: 0 !important;
      }
      .project-card, .event-card, .value-card {
        width: 30% !important;
        min-width: 30% !important;
        max-width: 30% !important;
        flex-shrink: 0 !important;
      }

      /* Desktop: skillset + events filter tabs stay on a single line (container widened above to make room) */
      .skillset-tabs-grid, .events-filter-bar {
        flex-wrap: nowrap !important;
        column-gap: 6px !important;
      }
      .skillset-tabs-grid .tab-row-break, .events-filter-bar .tab-row-break {
        display: none !important;
      }
      .skill-tab, .event-filter-btn {
        padding: 0 8px !important;
      }
      /* Arrow navigation buttons (desktop only) */
      .carousel-wrap { position: relative; }
      .carousel-arrow {
        display: flex;
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        width: 40px;
        height: 40px;
        border-radius: 50%;
        background: var(--bg-surface);
        border: 1px solid var(--border-color);
        box-shadow: 0 2px 10px rgba(15,23,42,0.12);
        align-items: center;
        justify-content: center;
        cursor: pointer;
        z-index: 20;
        color: var(--text-primary);
        transition: opacity 0.2s ease, background 0.15s ease;
      }
      .carousel-arrow.prev { left: -14px; }
      .carousel-arrow.next { right: -14px; }
      .carousel-arrow:disabled { opacity: 0.3; cursor: default; }

      .section-title {
        font-size: 26px;
      }
      .card-description, .value-card-text, .personal-statement {
        font-size: calc(1em + 1px);
      }
    }
    /* Arrows are hidden on mobile (touch swipe instead) */
    @media (max-width: 1023px) {
      .carousel-arrow { display: none !important; }
    }

/* --- Skillsets component base classes (see parts/04_skills.html) ---------------
 * These properties used to be repeated as an identical inline `style="..."`
 * attribute on every skill-tab button and every skill row (dozens of times,
 * byte-for-byte identical). Moved here so each element only carries the class
 * name plus whatever is genuinely per-element (a data-skillset value, or the
 * one dynamic progress-bar width). Visuals/behavior are unchanged: the JS in
 * script.js still toggles element.style.display / .style.width directly when
 * switching tabs, and inline styles always win over these class rules. */
.skill-tab {
  flex: 0 1 auto;
  height: 28px;
  padding: 0px 10px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: nowrap;
  color: var(--text-primary);
}
.skill-tab.active {
  background: var(--accent-primary);
  border: 1px solid var(--accent-primary);
  color: #FFFFFF;
}

.skill-row {
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  height: 24px;
}
/* "ai" is the default open skillset tab on first paint (see .skill-tab.active above) */
.skill-row[data-category="ai"] {
  display: flex;
}
.skill-name {
  font-family: var(--font-primary);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  width: 150px;
  flex-shrink: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.progress-track {
  flex-grow: 1;
  height: 4px;
  background: #E2E8F0;
  border-radius: 2px;
  overflow: hidden;
  position: relative;
}
.progress-fill {
  height: 100%;
  background: var(--accent-primary);
  border-radius: 2px;
  transition: width 0.8s cubic-bezier(0.4, 0, 0.2, 1);
}
.skill-percentage {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  color: var(--accent-primary);
  width: 38px;
  text-align: right;
  flex-shrink: 0;
}
