/*
Theme Name:   Hello Elementor Child - SAS Portfolio
Theme URI:    https://sajibahmedshawon.com
Description:  Child theme for the Sajib Ahmed Shawon portfolio. Holds the motion and micro-interaction layer that Elementor widget settings cannot express. All layout lives in Elementor; nothing here replaces a widget.
Author:       Sajib Ahmed Shawon
Template:     hello-elementor
Version:      1.0.0
Text Domain:  hello-elementor-child
*/

/* ============================================================
   Design tokens - mirror of the Elementor Global Styles kit.
   Kept here so hand-written rules below read like the source.
   ============================================================ */
:root{
  --ink:#080A14;
  --surface:#101426;
  --surface-2:#161B33;
  --border:rgba(76,111,255,0.18);
  --border-soft:rgba(255,255,255,0.07);
  --indigo:#4C6FFF;
  --periwinkle:#C9D4FF;
  --teal:#22D3EE;
  --text:#EDEEF2;
  --muted:#7C82A0;
  --muted-2:#4A4E63;
  --amber:#F5A524;
  --success:#34D399;
  --display:'Sora',sans-serif;
  --sans:'Inter',sans-serif;
  --mono:'IBM Plex Mono',monospace;
}

/* overflow-x:clip, never hidden. `hidden` on body makes body a scroll
   container (overflow-y computes to auto), which breaks position:sticky,
   scroll-triggered widget animations and IntersectionObserver timing. */
html{ scroll-behavior:smooth; overflow-x:clip; background:var(--ink); }
body{ background:var(--ink); color:var(--text); overflow-x:clip; }

/* Selection + focus ring, themed */
::selection{ background:rgba(76,111,255,0.32); color:#fff; }
:focus-visible{ outline:2px solid var(--indigo); outline-offset:3px; }

/* Themed scrollbar */
@media (min-width:1025px){
  ::-webkit-scrollbar{ width:10px; }
  ::-webkit-scrollbar-track{ background:var(--ink); }
  ::-webkit-scrollbar-thumb{ background:#1d2440; border-radius:10px; border:2px solid var(--ink); }
  ::-webkit-scrollbar-thumb:hover{ background:#2a3358; }
}

/* ============================================================
   Custom cursor
   ============================================================ */
.sas-cursor-dot,.sas-cursor-ring{
  position:fixed; top:0; left:0; z-index:9999; pointer-events:none;
  transform:translate(-50%,-50%); border-radius:50%;
  opacity:0; transition:opacity .3s ease;
}
body.sas-has-cursor .sas-cursor-dot,
body.sas-has-cursor .sas-cursor-ring{ opacity:1; }
.sas-cursor-dot{
  width:7px; height:7px; background:var(--indigo);
  box-shadow:0 0 10px rgba(76,111,255,0.7);
}
.sas-cursor-ring{
  width:42px; height:42px; border:1px solid rgba(124,147,255,0.45);
  display:flex; align-items:center; justify-content:center;
  transition:width .35s cubic-bezier(.2,.8,.2,1), height .35s cubic-bezier(.2,.8,.2,1),
             background .35s ease, border-color .35s ease, opacity .3s ease;
}
.sas-cursor-ring span{
  font-family:var(--mono); font-size:11px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--periwinkle); opacity:0; transition:opacity .25s ease; white-space:nowrap;
}
.sas-cursor-ring.is-active{
  width:88px; height:88px; background:rgba(76,111,255,0.14); border-color:var(--indigo);
}
.sas-cursor-ring.is-active span{ opacity:1; }
.sas-cursor-ring.is-link{ width:60px; height:60px; background:rgba(76,111,255,0.1); }

@media (hover:none),(pointer:coarse){
  .sas-cursor-dot,.sas-cursor-ring{ display:none !important; }
}

/* ============================================================
   Scroll reveal - applied via the "sas-reveal" CSS class
   on any Elementor container or widget.
   ============================================================ */
.sas-reveal{
  opacity:0; transform:translateY(26px);
  transition:opacity .7s cubic-bezier(.2,.8,.2,1), transform .7s cubic-bezier(.2,.8,.2,1);
  will-change:opacity,transform;
}
.sas-reveal.in{ opacity:1; transform:none; }
.sas-reveal.d1{ transition-delay:.08s; }
.sas-reveal.d2{ transition-delay:.16s; }
.sas-reveal.d3{ transition-delay:.24s; }
.sas-reveal.d4{ transition-delay:.32s; }

/* ============================================================
   Card tilt + magnetic buttons
   JS writes the transform; CSS owns the easing back.
   ============================================================ */
.sas-tilt{ transition:transform .45s cubic-bezier(.2,.8,.2,1), border-color .35s ease, box-shadow .45s ease; transform-style:preserve-3d; }
.sas-magnetic{ transition:transform .35s cubic-bezier(.2,.8,.2,1); }

/* ============================================================
   Hero: animated growth curve + cursor glow
   ============================================================ */
.sas-hero{ position:relative; overflow:hidden; isolation:isolate; }
/* The curve is an external SVG that carries its own animation, so it
   draws itself without any inline markup in the page. */
/* Site-wide CTA hover consistency - every .btn-primary/.btn-outline/
   .whatsapp-cta equivalent gets the reference's own hover treatment.
   The lift+scale on hover comes from bindMagnetic() in site.js (shared
   by every element with .sas-magnetic) - only color/background/shadow
   need CSS here. */

/* Nav "Hire Me" - .nav-cta:hover in the reference. Deliberately NOT
   using the shared magnetic-button JS here (unlike the hero CTAs) -
   the header needs zero layout shift and a restrained, static
   translateY(-2px) only, matching the reference's own .nav-cta:hover
   exactly (no scale, no cursor-follow). width/height/padding/font are
   untouched so the header's own height never changes on hover. */
.elementor-element-18ec30e .elementor-button{
  transition:background-image .3s, box-shadow .3s, transform .3s;
}
.elementor-element-18ec30e .elementor-button:hover{
  background-image:linear-gradient(135deg, var(--periwinkle), var(--indigo)) !important;
  box-shadow:0 12px 26px -8px rgba(76,111,255,0.55);
  transform:translateY(-2px);
}

/* Resume "Request Full Resume" - .cv-download:hover in the reference:
   the outline pill fills solid on hover instead of just tinting. */
.elementor-element-6695b5b .elementor-button:hover{
  background-color:var(--indigo) !important;
  border-color:var(--indigo) !important;
  color:#0A0B10 !important;
  box-shadow:0 14px 30px -10px rgba(76,111,255,0.5);
}

/* WhatsApp CTA - .whatsapp-cta:hover in the reference */
.elementor-element-8983dd1 .elementor-button:hover{
  background-color:rgba(124,147,255,0.12) !important;
  box-shadow:0 12px 28px -12px rgba(34,211,238,0.4);
}

/* Blog "View All Articles" - built with plain solid colors instead of
   the shared .btn-primary gradient + dark text; correcting both the
   resting state and hover here since the widget settings can't express
   a CSS gradient. */
.elementor-element-5220142 .elementor-button{
  background-color:transparent !important;
  background-image:linear-gradient(135deg, var(--indigo), #7B93FF) !important;
  color:#0A0B10 !important;
}
.elementor-element-5220142 .elementor-button:hover{
  background-image:linear-gradient(135deg, var(--periwinkle), var(--indigo)) !important;
  color:#0A0B10 !important;
  box-shadow:0 12px 26px -8px rgba(76,111,255,0.55);
}

/* Hero CTA hover animations, matching the reference's .btn-primary/
   .btn-outline/.btn-ghost :hover states exactly. Scoped to each button's
   own element id so nothing else sharing .elementor-button is touched. */
.elementor-element-3f35084 .elementor-button{
  transition:all .35s cubic-bezier(.2,.8,.2,1) !important;
}
.elementor-element-3f35084 .elementor-button:hover{
  background-image:linear-gradient(135deg, var(--periwinkle), var(--indigo)) !important;
  transform:translateY(-3px) scale(1.02);
  box-shadow:0 18px 38px -10px rgba(76,111,255,0.6);
}
.elementor-element-88a22aa .elementor-button{
  transition:all .35s cubic-bezier(.2,.8,.2,1) !important;
}
.elementor-element-88a22aa .elementor-button:hover{
  border-color:var(--teal) !important; color:var(--teal) !important;
  background-color:rgba(34,211,238,0.08) !important;
  transform:translateY(-3px);
}
.elementor-element-dc71b1a .elementor-button{
  transition:all .35s cubic-bezier(.2,.8,.2,1) !important;
}
.elementor-element-dc71b1a .elementor-button-icon{
  display:inline-block; transition:transform .3s cubic-bezier(.2,.8,.2,1);
}
.elementor-element-dc71b1a .elementor-button:hover .elementor-button-icon{
  transform:translateX(5px);
}

.sas-gradient-mesh{
  position:absolute; inset:-10%; z-index:0; pointer-events:none;
  background:
    radial-gradient(ellipse 800px 500px at 85% 15%, rgba(76,111,255,0.16), transparent 60%),
    radial-gradient(ellipse 700px 500px at 5% 90%, rgba(124,147,255,0.1), transparent 60%),
    radial-gradient(ellipse 600px 460px at 50% 50%, rgba(76,111,255,0.06), transparent 65%);
  background-size:140% 140%; will-change:transform;
  animation:sasMeshDrift 18s ease-in-out infinite alternate;
}
@keyframes sasMeshDrift{
  0%{ transform:translate3d(0,0,0); }
  100%{ transform:translate3d(15px,10px,0); }
}
@media (prefers-reduced-motion: reduce){ .sas-gradient-mesh{ animation:none; } }

.sas-hero-graph{
  position:absolute; inset:0; width:100%; height:100%;
  z-index:0; pointer-events:none; opacity:.85;
  background-image:url('assets/hero-graph.svg');
  background-repeat:no-repeat;
  background-position:center bottom;
  background-size:100% 100%;
  will-change:transform;
}

.sas-cursor-glow{
  position:absolute; top:0; left:0; width:460px; height:460px;
  border-radius:50%; pointer-events:none; z-index:1;
  background:radial-gradient(circle, rgba(76,111,255,0.16) 0%, rgba(76,111,255,0.05) 45%, transparent 70%);
  opacity:0; transition:opacity .5s ease;
}
.sas-hero:hover .sas-cursor-glow{ opacity:1; }

/* Scroll indicator */
.sas-scroll-indicator{ transition:opacity .4s ease, transform .4s ease; cursor:pointer; }
.sas-scroll-indicator.hidden{ opacity:0; transform:translateY(12px); pointer-events:none; }
/* Rotating ring + pulsing dot, matching the reference's own
   .scroll-ring/.scroll-dot exactly - replaces an earlier "mouse wheel"
   shape that never matched the source file at all. */
.sas-scroll-indicator .sas-scroll-ring{
  position:relative; width:52px; height:52px; border-radius:50%;
  border:1px solid rgba(124,147,255,0.35);
  display:flex; align-items:center; justify-content:center;
  margin:0 auto;
}
.sas-scroll-indicator .sas-scroll-ring::before{
  content:''; position:absolute; inset:-1px; border-radius:50%;
  border:1px solid transparent; border-top-color:var(--indigo);
  animation:sas-ring-spin 3s linear infinite;
}
.elementor-13 .elementor-element.elementor-element-f7c9e42.sas-scroll-dot,
.sas-scroll-indicator .sas-scroll-dot{
  width:7px !important; height:7px !important; min-width:0 !important; max-width:7px !important;
  border-radius:50%; background:var(--indigo);
  box-shadow:0 0 14px 2px rgba(76,111,255,0.6);
  animation:sas-dot-pulse 1.8s ease infinite;
}
@keyframes sas-ring-spin{ to{ transform:rotate(360deg); } }
@keyframes sas-dot-pulse{ 0%,100%{ transform:scale(1); opacity:1; } 50%{ transform:scale(1.5); opacity:0.6; } }
@media (prefers-reduced-motion: reduce){
  .sas-scroll-ring::before{ animation:none; }
  .sas-scroll-dot{ animation:none; }
}

/* ============================================================
   Section rhythm + dividers
   ============================================================ */
.sas-divider{
  height:1px; width:100%;
  background:linear-gradient(90deg,transparent,var(--border),transparent);
}

/* Reduce 5px padding on every homepage section except #home */
#about > .e-con-inner {
  padding-top: 35px !important;
  padding-bottom: 75px !important;
}
#services > .e-con-inner,
#portfolio > .e-con-inner,
#certifications > .e-con-inner,
#resume > .e-con-inner,
#contact > .e-con-inner,
#blog > .e-con-inner {
  padding-top: 75px !important;
  padding-bottom: 75px !important;
}

/* Fixed header scroll offset for all sections */
#about, #services, #portfolio, #certifications, #resume, #contact, #blog {
  scroll-margin-top: 90px !important;
}

/* CookieYes GDPR Consent visibility guarantee */
[data-cky-tag] {
  visibility: visible !important;
}
.cky-consent-container {
  z-index: 99998 !important;
}
.cky-btn {
  cursor: pointer !important;
  pointer-events: auto !important;
}

/* Elementor Popup Modal & Close Button */
.dialog-close-button.dialog-lightbox-close-button {
  position: absolute !important;
  top: 16px !important;
  right: 16px !important;
  width: 44px !important;
  height: 44px !important;
  min-width: 44px !important;
  min-height: 44px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  cursor: pointer !important;
  z-index: 10000 !important;
  border-radius: 50% !important;
  background: rgba(255, 255, 255, 0.10) !important;
  border: 1px solid rgba(255, 255, 255, 0.20) !important;
  color: #EDEEF2 !important;
  pointer-events: auto !important;
  transition: background 0.2s ease, transform 0.2s ease !important;
}
.dialog-close-button.dialog-lightbox-close-button:hover {
  background: rgba(255, 255, 255, 0.22) !important;
  transform: scale(1.05) !important;
}
.dialog-close-button.dialog-lightbox-close-button svg {
  width: 18px !important;
  height: 18px !important;
  min-width: 18px !important;
  min-height: 18px !important;
  fill: currentColor !important;
  display: block !important;
}

/* Eyebrow label - TEAL in the reference, not indigo */
.sas-eyebrow .elementor-heading-title,
.sas-eyebrow{
  font-family:var(--mono); font-size:13px; font-weight:700; letter-spacing:2.16px;
  text-transform:uppercase; color:var(--teal);
}
/* The actual text lives in a nested .elementor-heading-title element, which
   has its own font-size from Elementor's widget defaults - the rule above
   only reaches the outer wrapper div, so it never actually resized the real
   text. Targeting the real element directly, with !important since Elementor
   widget typography can come from an inline style. */
.sas-eyebrow .elementor-heading-title{
  font-size:14px !important; font-weight:700 !important; line-height:1.6 !important;
  color:var(--teal) !important;
}
.e-con > .e-con-inner > .sas-eyebrow{ margin-bottom:18px; }

/* Hero card is an outlined panel, not a filled surface */
.sas-hero .sas-card{
  background:transparent !important;
  border-radius:6px;
  padding:34px !important;
  min-height:500px;
}

/* ============================================================
   Loop item cards - certificates, projects, services
   Structure is Elementor containers; this is surface + state only.
   ============================================================ */
/* Radii come straight from the reference: service cards are square and sit in
   a 1px-gap slab, result cards 8px, certificates 6px. 16px everywhere was the
   single biggest reason the rebuild read as a different site. */
.sas-card{
  background:var(--surface); border:1px solid var(--border-soft); border-radius:6px;
  position:relative; overflow:hidden; height:100%;
  transition:border-color .3s ease, box-shadow .3s ease, background .3s ease;
}
#services .sas-card{ border-radius:0; padding:38px 34px !important; }
#portfolio .sas-card{ border-radius:8px; padding:0 !important; }
#certifications .sas-card{ border-radius:6px; padding:36px 24px !important; }
#blog .sas-card{ border-radius:8px; padding:0 !important; }

/* Result card body padding lives on the inner block, since the card itself is flush */
#portfolio .sas-card > .e-con:last-child{ padding:24px 28px 28px !important; }
#blog .sas-card > .e-con:last-child{ padding:24px !important; }
#portfolio .sas-shot,
#blog .sas-shot{ padding:0 !important; border-radius:0; border:none; }
#portfolio .sas-shot img,
#blog .sas-shot img{ border-radius:0 !important; }
.sas-card:hover{ border-color:var(--border); box-shadow:0 18px 48px -24px rgba(76,111,255,0.5); }
.sas-card::before{
  content:''; position:absolute; inset:0; border-radius:16px; pointer-events:none;
  background:linear-gradient(140deg,rgba(76,111,255,0.10),transparent 42%);
  opacity:0; transition:opacity .45s ease;
}
.sas-card:hover::before{ opacity:1; }

/* ------------------------------------------------------------
   Section headers.

   A column flex container with align-items:center shrink-wraps every
   block child to its own text width, so each section's eyebrow/title/
   subtitle ended up a different width (67px / 558px / 729px) and the
   text measure was whatever the copy happened to be. Give them the full
   column and control the measure explicitly instead.
   ------------------------------------------------------------ */
.e-con > .e-con-inner > .elementor-widget-heading,
.e-con > .e-con-inner > .elementor-widget-text-editor{
  width:100%;
}
.e-con > .e-con-inner > .elementor-widget-text-editor .elementor-widget-container{
  max-width:68ch;
  margin-inline:auto;
}

/* ------------------------------------------------------------
   Cards fill their grid cell, and the body grows so that cards with
   shorter copy still line their bottom edges up with their neighbours.
   ------------------------------------------------------------ */
.elementor-loop-container > .e-loop-item{ display:flex; }
.elementor-loop-container > .e-loop-item > .e-con{ width:100%; }
.sas-card{ display:flex; flex-direction:column; }
.sas-card > .e-con:last-child{ flex:1 1 auto; }

/* Push a card's trailing text block to fill remaining space so the
   card never ends with a ragged gap under short copy. */
.sas-card .elementor-widget-theme-post-excerpt{ margin-top:auto; }

/* Service number watermark */
.sas-svc-num .elementor-heading-title{
  font-family:var(--mono); font-size:13px; color:var(--muted-2); letter-spacing:.14em;
}

/* Stat chips: teal on a teal wash, 4px radius - not indigo pills.
   The reference uses teal for eyebrows/tags/stats and reserves indigo
   for primary actions and progress fills. */
.sas-stat .elementor-heading-title,
.sas-stat{
  display:inline-block; font-family:var(--mono); font-size:11.5px;
  color:var(--teal); background:rgba(34,211,238,0.07);
  border:none; border-radius:4px; padding:4px 9px;
}
/* Project channel tag */
#portfolio .sas-eyebrow .elementor-heading-title{
  color:var(--teal); font-size:11px; letter-spacing:1.1px; text-transform:uppercase;
}
/* An empty stat chip (project with fewer than three stats) collapses */
.sas-stat .elementor-heading-title:empty{ display:none; }
.sas-stat:has(.elementor-heading-title:empty){ display:none; }

/* ------------------------------------------------------------
   Project screenshot frame.

   The source screenshots range from 1.23 to 3.02 in aspect ratio, so
   letting them size themselves made card heights swing 352px - 619px
   with dead whitespace beside the short ones. Pinning one ratio and
   cropping with object-fit:cover (never `fill`, which distorts) makes
   every card in a row the same height.
   ------------------------------------------------------------ */
.sas-shot{
  border-radius:12px; overflow:hidden;
  border:1px solid var(--border-soft);
  background:linear-gradient(140deg,#161B33,#0E1224);
}
.sas-shot .elementor-widget-theme-post-featured-image,
.sas-shot .elementor-widget-container,
.sas-shot figure,
.sas-shot a{ display:block; height:100%; }

.sas-shot img{
  display:block;
  width:100%;
  aspect-ratio:16/10;
  height:auto;
  object-fit:cover;      /* crop, never squash */
  object-position:top center; /* screenshots read from the top-left */
}
/* Meta Ads project image (attachment 125) is a wide dashboard screenshot
   (2.3:1) - far wider than this card's own 16:10 crop box. object-fit:cover
   with that mismatch crops off both edges (Campaign Name column on the left,
   CTR Click Rate on the right). Scoped to just this one attachment so every
   other portfolio card keeps its normal cover-fit crop behavior. contain
   guarantees the full screenshot - every column - is always visible, with
   the card's own dark gradient showing through as letterbox padding instead
   of cropping any content away. */
/* Meta Ads project image (attachment 125): tried object-fit:contain with a
   matching aspect-ratio to avoid cropping any column, but that made this
   one card visibly shorter than every sibling card in the grid - user
   wants matching box size across all cards more than showing every last
   column, so this image now uses the exact same 16/10 cover-crop as
   everything else (no override needed - it just falls through to the
   shared `.sas-shot img` rule above). Kept as a comment, not deleted
   outright, so the reasoning survives if this needs revisiting. */

/* A project with no screenshot yet keeps the same footprint instead of
   collapsing and dragging its row out of alignment. */
.sas-shot:not(:has(img))::after{
  content:'';
  display:block;
  aspect-ratio:16/10;
  background:
    radial-gradient(circle at 30% 30%, rgba(76,111,255,0.16), transparent 60%),
    repeating-linear-gradient(135deg, rgba(255,255,255,0.03) 0 10px, transparent 10px 20px);
}

/* ============================================================
   Client logo carousel - circular marks, edge fade
   ============================================================ */
.sas-marquee{ position:relative; }
.sas-marquee::before,.sas-marquee::after{
  content:''; position:absolute; top:0; bottom:0; width:140px; z-index:2; pointer-events:none;
}
.sas-marquee::before{ left:0; background:linear-gradient(90deg,var(--ink),transparent); }
.sas-marquee::after{ right:0; background:linear-gradient(270deg,var(--ink),transparent); }
/* Only 2 clients exist right now - Elementor's Loop Grid spreads them
   across two full-width equal columns (each ~646px), leaving a huge
   gap between the two small circles. Flex + center keeps them close
   together regardless of how many clients exist later (grows naturally
   if more are added, still centered as a group). */
.elementor-element-17db3c4 .elementor-loop-container{
  display:flex !important; flex-wrap:wrap; justify-content:center;
}
.sas-marquee img{
  width:110px; height:110px; border-radius:50%; object-fit:cover;
  border:1px dashed rgba(255,255,255,0.18); background:var(--surface-2); padding:0;
  filter:grayscale(1); opacity:.72; transition:filter .4s ease, opacity .4s ease, transform .4s ease;
}
.sas-marquee img:hover{ filter:none; opacity:1; transform:scale(1.06); }
/* Touch devices have no hover state, so the dim/grayscale treatment above
   would otherwise be permanent - logos would never reach full clarity.
   Show them at full color/opacity by default wherever hover isn't available. */
@media (hover:none){
  .sas-marquee img{ filter:none; opacity:1; }
}

/* ============================================================
   Progress bars (resume skills)
   ============================================================ */
.sas-skill .elementor-progress-wrapper{
  background:rgba(255,255,255,0.05); border-radius:999px; height:6px; overflow:hidden;
}
.sas-skill .elementor-progress-bar{
  background:linear-gradient(90deg,var(--indigo),var(--teal));
  border-radius:999px; height:6px;
}
.sas-skill .elementor-progress-percentage{
  font-family:var(--mono); color:var(--periwinkle); font-size:13px;
}

/* ============================================================
   Elementor Pro form - themed to the dark surface
   ============================================================ */
.sas-form .elementor-field-group{ margin-bottom:4px; }
.sas-form .elementor-field-type-text input,
.sas-form .elementor-field-type-email input,
.sas-form .elementor-field-type-url input,
.sas-form .elementor-field-type-tel input,
.sas-form .elementor-field-type-textarea textarea,
.sas-form .elementor-field-type-select select{
  background:var(--surface-2) !important;
  border:1px solid var(--border-soft) !important;
  border-radius:3px !important;
  color:var(--text) !important;
  padding:13px 14px !important;
  font-family:var(--sans); font-size:14.5px;
  transition:border-color .3s ease, box-shadow .3s ease, background .3s ease;
}
/* Textarea only - matches .field textarea{min-height:110px} in the reference.
   Scoped separately from the shared input/select rule above; a stray comma
   there once applied this to <select> too, turning every dropdown into a
   110px-tall empty box - fixed in the same pass as the submit button. */
.sas-form .elementor-field-type-textarea textarea{ min-height:110px; }

.sas-form input:focus,.sas-form textarea:focus,.sas-form select:focus{
  border-color:var(--indigo) !important;
  box-shadow:0 0 0 3px rgba(76,111,255,0.16) !important;
  background:#19203c !important;
}
.sas-form .elementor-field-label{
  color:var(--muted) !important; font-family:var(--mono);
  font-size:12px; letter-spacing:.08em; text-transform:uppercase; margin-bottom:7px;
}
.sas-form input::placeholder,.sas-form textarea::placeholder{ color:var(--muted-2); }
.sas-form .elementor-field-type-upload input[type=file]{
  color:var(--muted) !important; font-family:var(--sans); font-size:13.5px;
  background:var(--surface-2) !important; border:1px solid var(--border-soft) !important;
  border-radius:3px; padding:11px 14px; width:100%; cursor:pointer;
}
.sas-form .elementor-field-type-upload input[type=file]:hover{ border-color:var(--indigo) !important; }
.sas-form .elementor-field-type-upload input[type=file]::file-selector-button{
  background:linear-gradient(135deg, var(--indigo), #7B93FF); color:#0A0B10; font-weight:700; border:none; border-radius:6px;
  padding:8px 16px; margin-right:14px; font-family:var(--sans); font-size:13px; cursor:pointer;
}
.sas-form .elementor-message{ font-family:var(--mono); font-size:13px; }
.sas-form .elementor-message.elementor-message-success{ color:var(--success); }
.sas-form select option{ background:var(--surface-2); color:var(--text); }

/* ============================================================
   Animated headline - the rotating words are absolutely
   positioned, so the wrapper must never widen its card.
   ============================================================ */
.elementor-widget-animated-headline .elementor-headline,
.elementor-widget-animated-headline .elementor-headline-dynamic-wrapper{
  max-width:100%; overflow:hidden;
}

/* ============================================================
   Mobile navigation - full-height OPAQUE overlay.

   The live bug was a dropdown sized to its own content with a
   translucent surface, so page content bled through behind the links.
   It is now a fixed overlay from under the header to the bottom of the
   viewport, on a fully solid --ink ground.
   ============================================================ */
/* Reference: header{position:fixed; top:0; left:0; right:0; z-index:100;} verbatim.
   Elementor's native "sticky" setting only engages position:fixed after a scroll
   event fires, so at rest (scrollY 0) the row sat in normal flow and pushed the
   hero down by its own height. Unconditional fixed positioning removes that
   dependency on JS timing and matches the reference exactly at every scroll position. */
.sas-header{
  position:fixed; top:0; left:0; right:0; z-index:100;
  background-color: rgba(8, 10, 20, 0.75) !important;
  backdrop-filter: blur(16px) saturate(160%) !important;
  -webkit-backdrop-filter: blur(16px) saturate(160%) !important;
  border-bottom: 1px solid rgba(76, 111, 255, 0.18) !important;
  transition: border-color .25s ease, box-shadow .25s ease, background-color .25s ease;
}
.sas-header.is-scrolled{
  background-color: rgba(8, 10, 20, 0.94) !important;
  border-bottom: 1px solid rgba(76, 111, 255, 0.38) !important;
  box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.8), 0 1px 0 0 rgba(34, 211, 238, 0.20) !important;
}
/* Logged-in only: WP's admin bar is position:fixed at the true viewport
   top too, so our own fixed header (also top:0) sits underneath/behind
   it instead of shifting down - push it below the admin bar at both of
   WP's own admin-bar breakpoints (32px above 782px, 46px at/below it,
   matching wp-includes/css/admin-bar.min.css exactly). Never affects an
   actual visitor - body.admin-bar only exists while logged in. */
body.admin-bar .sas-header{ top:32px; }
@media screen and (max-width:782px){
  body.admin-bar .sas-header{ top:46px; }
}

/* Elementor Pro's own widget-nav-menu.min.css hardcodes height:3px for the
   underline pointer style (not exposed as a widget setting) - reference
   wants a thin 1px line. Scoped to this one nav-menu widget only. */
.elementor-62 .elementor-element.elementor-element-9a4b2f8 .elementor-item::after,
.elementor-62 .elementor-element.elementor-element-9a4b2f8 .elementor-item::before{
  height:1px !important;
}
/* Nav breakpoint: match the reference's exact 900px switch point. Elementor's
   nav-menu widget only offers stock breakpoint tiers for its own dropdown
   setting - "tablet" switches to the burger at its default upper bound,
   1024px, not 900px. That left two problems: the burger showed across
   901-1024px (should be desktop nav there), and the CTA - hidden only via
   elementor-hidden-mobile, Elementor's <=767px tier - stayed visible
   alongside the burger across the whole 768-1024px gap. Scoped to .sas-nav
   so it can't affect anything outside the header. */
@media (min-width:901px) and (max-width:1024px){
  .sas-nav .elementor-nav-menu--main{ display:flex !important; }
  .sas-nav .elementor-menu-toggle{ display:none !important; }
  /* Elementor's nav <ul> defaults to flex-wrap:wrap, and at this width the
     7 links + their 14px item padding sit right at the edge of fitting -
     "Blog" wraps to its own row. Trim item padding only in this narrow
     band so it reliably stays one line without touching the 38px gap or
     font-size the reference specifies for desktop. */
  .sas-nav .elementor-nav-menu{ flex-wrap:nowrap !important; }
  .sas-nav .elementor-nav-menu .elementor-item{ padding-left:8px !important; padding-right:8px !important; }
}
@media (max-width:900px){
  .sas-nav-cta{ display:none !important; }
}
/* The header logo is an inline SVG icon widget (.logo-svg, defined further
   down as height:42px!important; width:auto - NOT an <img>, so the earlier
   .sas-header img rule never touches it), which never shrinks with
   viewport - at 320-364px the logo (264.6px) + hamburger (44px) + 24px gap
   (332.6px) exceeds the available row width, and .e-con-inner's default
   flex-wrap:wrap drops the hamburger to its own row below the logo instead
   of shrinking anything. Shrink the logo height and tighten the row gap
   specifically below that breakeven width. */
@media (max-width:400px){
  .sas-header .logo-svg{ height:30px !important; }
  .sas-header .e-con-inner{ gap:12px !important; }
}

.sas-nav .elementor-menu-toggle{
  background:rgba(76,111,255,0.10);
  border:1px solid rgba(76,111,255,0.18);
  border-radius:10px; padding:9px;
  position:relative; z-index:160;   /* stays clickable above the overlay */
}

/* header nav{height:78px} in the reference, verbatim - not a device-width
   hack. The dropdown's top:78px below is exact against this, not approximate. */
.sas-header, .sas-header > .e-con-inner, #section-nav{ height: 90px !important; min-height: 90px !important; }

/* Elementor writes `top`/`width` inline and collapses the dropdown with
   transform:scaleY(0) + max-height:0 pending its open animation; every
   property here needs !important to win over that and be deterministic.

   Sized to CONTENT, not the viewport - this matches the reference's own
   `.mobile-menu{position:fixed; top:78px; left:0; right:0; background:
   var(--surface); ...}` exactly. It has no `bottom`/`height`: it is a
   solid dropdown that slides down over the links' own height, not a
   full-screen takeover. Solid + opaque already means nothing shows
   through the dropdown's own box, which is the actual requirement. */
/* Real element (#sas-menu-backdrop, appended straight to <body> by JS) -
   see the .sas-nav::before comment history for why a pseudo-element
   nested inside the fixed header didn't reliably paint above page
   content; a body-level sibling sidesteps any nested-stacking-context
   ambiguity entirely. */
#sas-menu-backdrop{
  position:fixed !important; top:90px !important; left:0 !important; right:0 !important; bottom:0 !important;
  background:var(--surface) !important; z-index:98 !important; pointer-events:none !important;
  display:none;
}
body.sas-menu-open #sas-menu-backdrop{ display:block; }
@media (max-width: 1024px) {
  body:not(.sas-menu-open) .sas-nav .elementor-nav-menu--dropdown{
    display:none !important;
    max-height:0 !important;
    opacity:0 !important;
    visibility:hidden !important;
    pointer-events:none !important;
  }
}
body.sas-menu-open .sas-nav .elementor-nav-menu--dropdown{
  display:block !important;
  position:fixed !important;
  top:90px !important;
  left:0 !important;
  right:0 !important;
  width:auto !important;
  max-width:none !important;
  transform:none !important;
  max-height:calc(100dvh - 90px) !important;
  margin:0 !important;
  background:var(--surface) !important;   /* solid #101426, per the reference */
  border-bottom:1px solid var(--border-soft);
  border-radius:0 !important;
  box-shadow:none !important;
  padding:20px 32px !important;
  overflow-y:auto !important;
  overscroll-behavior:contain;
  z-index:99 !important;
}
body.sas-menu-open .sas-nav .elementor-nav-menu--dropdown .elementor-nav-menu{
  display:flex !important; flex-direction:column !important; gap:6px !important;
  background:transparent !important;
}
.sas-nav .elementor-nav-menu--dropdown a{
  font-family:var(--sans);
  padding:14px 0 !important;
  font-size:15px;
  color:var(--muted);
  border-bottom:1px solid var(--border-soft);
  background:transparent !important;
}
.sas-nav .elementor-nav-menu--dropdown li:last-child a{ border-bottom:none; }

/* ============================================================
   Contact form - animated gradient border on focus
   ============================================================ */
.sas-form-wrap{ position:relative; border-radius:8px; }
/* Contact section is static per explicit request - the rotating conic-
   gradient focus border is disabled outright rather than just not
   triggered, so no stray rule can ever animate it back on. */
.sas-form-wrap::before{ content:none !important; display:none !important; animation:none !important; }

/* Belt-and-suspenders: no decorative motion anywhere in #contact. Values
   only (transform/transition/animation/visibility) - never color,
   background, border-color, font-family or fill, so Elementor's own
   configured styling is untouched. */
#contact .sas-form-wrap,
#contact .sas-form,
#contact .elementor-field-group,
#contact .elementor-field,
#contact .elementor-button{
  animation:none !important; transition:none !important; transform:none !important;
}
#contact .elementor-invisible{ visibility:visible !important; }
.sas-form-wrap > .e-con-inner,
.sas-form-wrap > .elementor-widget-wrap{ position:relative; z-index:1; }

/* Submit button: full width, matching .form-submit{width:100%} in the
   reference. Elementor's own "Column Width" control (button_width) turned
   out not to generate any width rule for a single-button form - verified by
   reading its actual generated CSS, not assumed - so this is set directly
   here instead of fought for in the widget settings. */
.sas-form form button[type=submit]{
  width:100%;
  box-shadow:0 10px 26px -10px rgba(76,111,255,0.55);
}
.elementor-13 .elementor-element.elementor-element-80f405a .elementor-button[type="submit"],
.sas-form form button[type=submit]{
  background-color:transparent !important;
  background-image:linear-gradient(135deg, var(--indigo), #7B93FF) !important;
  color:#0A0B10 !important;
  font-weight:700 !important;
}
.elementor-13 .elementor-element.elementor-element-80f405a .elementor-button[type="submit"]:hover,
.sas-form form button[type=submit]:hover{
  background-image:linear-gradient(135deg, var(--periwinkle), var(--indigo)) !important;
}

/* WhatsApp CTA below the form - same full width as the Send Inquiry button,
   matching .whatsapp-cta in the reference (display:flex, no fixed width,
   naturally fills its parent - Elementor's Button widget defaults to
   content width instead, so it needs an explicit override here). */
.elementor-element-8983dd1.elementor-widget-button{ width:100%; }
/* This one button carries a much longer label ("Chat on WhatsApp: replies
   usually within a few hours") than any other button on the site, which
   all share a pill shape (border-radius:100px) sized for a short single
   line. Wrapped to 3 lines inside a full pill with centered text and
   line-height:1 (Elementor's own button default), it read as cramped and
   hard to read. Matches the reference's actual .whatsapp-cta treatment
   for this element specifically (flat card, left-aligned, comfortable
   leading) without touching the pill shape used everywhere else. */
/* Matches Send Inquiry's button type exactly (solid indigo gradient fill,
   dark bold text, shadow, full pill), same as .sas-form form
   button[type=submit] below. Label shortened to "Chat on WhatsApp" (was
   a full sentence that wrapped to 3 lines and needed left-align/looser
   leading to stay readable) - now a single short line like every other
   button, so no longer needs its own text-align/line-height overrides. */
.elementor-element-8983dd1 .elementor-button{
  width:100%;
  background-color:transparent !important;
  background-image:linear-gradient(135deg, var(--indigo), #7B93FF) !important;
  color:#0A0B10 !important; font-weight:700 !important;
  box-shadow:0 10px 26px -10px rgba(76,111,255,0.55);
}
.elementor-element-8983dd1 .elementor-button:hover{
  background-image:linear-gradient(135deg, var(--periwinkle), var(--indigo)) !important;
}

/* Submit button: spinner while sending, checkmark on success.
   Elementor ships no loading spinner of its own here, so both states are ours. */
.sas-form .elementor-button{ position:relative; }

.sas-form .elementor-button.sas-sending .elementor-button-text{ visibility:hidden; }
.sas-form .elementor-button.sas-sending::after{
  content:''; position:absolute; top:50%; left:50%;
  width:16px; height:16px; margin:-8px 0 0 -8px;
  border-radius:50%;
  border:2px solid rgba(255,255,255,0.35);
  border-top-color:#fff;
  /* Contact section is static per explicit request - no decorative
     motion, including the spinner's own rotation. The ring itself still
     shows (real sending-state feedback), it just doesn't spin. */
}

/* background-color, not the shorthand - Elementor sets background-color and
   the shorthand loses to it on specificity. */
.sas-form .elementor-button.sas-sent{ background-color:#22D3EE !important; }
.sas-form .elementor-button.sas-sent .elementor-button-text{ display:none; }
.sas-form .elementor-button.sas-sent .elementor-button-icon{ display:none; }
.sas-form .elementor-button.sas-sent::after{
  content:''; width:18px; height:18px; display:inline-block;
  background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3'%3E%3Cpath d='M4 12l5 5L20 6'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3'%3E%3Cpath d='M4 12l5 5L20 6'/%3E%3C/svg%3E") center/contain no-repeat;
  color:#08111A;
  animation:sas-check-pop .4s cubic-bezier(.2,.8,.2,1);
}
@keyframes sas-check-pop{ from{ transform:scale(.3); opacity:0; } to{ transform:scale(1); opacity:1; } }

/* ============================================================
   Resume skill boxes - four cards, matching .skill-box
   ============================================================ */
.sas-skill-box{
  background:var(--surface-2);
  border:1px solid var(--border-soft);
  border-radius:14px;
  transition:transform .45s cubic-bezier(.2,.8,.2,1), border-color .35s ease;
}
.sas-skill-box:hover{ border-color:var(--border); }
.sas-skill-box .sas-skill-icon svg{ width:22px; height:22px; }
.elementor-13 .elementor-element .sas-skill-pct .elementor-heading-title,
.sas-skill-box .sas-skill-pct .elementor-heading-title{
  font-family:'IBM Plex Mono',monospace !important; font-size:30px; font-weight:700; color:var(--text); line-height:1;
}
.sas-skill-box .sas-skill-name .elementor-heading-title{
  font-family:var(--sans); font-size:14px; color:var(--muted);
}

/* Staggered cascade for loop-grid children (services, skills, portfolio) */
.elementor-loop-container > .e-loop-item{ animation:sas-cascade .6s cubic-bezier(.2,.8,.2,1) both; }
.elementor-loop-container > .e-loop-item:nth-child(1){ animation-delay:.04s; }
.elementor-loop-container > .e-loop-item:nth-child(2){ animation-delay:.10s; }
.elementor-loop-container > .e-loop-item:nth-child(3){ animation-delay:.16s; }
.elementor-loop-container > .e-loop-item:nth-child(4){ animation-delay:.22s; }
.elementor-loop-container > .e-loop-item:nth-child(5){ animation-delay:.28s; }
.elementor-loop-container > .e-loop-item:nth-child(6){ animation-delay:.34s; }
.elementor-loop-container > .e-loop-item:nth-child(n+7){ animation-delay:.40s; }
@keyframes sas-cascade{ from{ opacity:0; transform:translateY(18px); } to{ opacity:1; transform:none; } }

/* ============================================================
   Footer - matched to the source markup
   ============================================================ */
.sas-footer-brand .sas-footer-tagline{ max-width:340px; margin:18px 0 24px; }

/* Compact wordmark SVG (icon + "Sajib Ahmed Shawon") - fixed height, width
   follows its own aspect ratio. !important because Elementor's per-element
   generated CSS (leftover width rules from an earlier, wider logo asset)
   otherwise wins the cascade and squashes/stretches this one. */
.sas-header img,
.sas-footer-brand .elementor-widget-image img{
  width:auto !important; height:auto !important; object-fit:contain !important;
}
.sas-header img{ height:42px !important; max-width:none !important; }
.sas-footer-brand .elementor-widget-image img{ height:46px !important; max-width:none !important; }

/* 42px social chips, muted until hover, then teal and lifted */
.sas-social .elementor-social-icon{
  width:42px; height:42px; border-radius:50%;
  border:1px solid var(--border-soft);
  background:transparent !important;
  color:var(--muted) !important;
  display:flex; align-items:center; justify-content:center;
  transition:border-color .25s ease, color .25s ease, transform .25s ease;
}
.sas-social .elementor-social-icon:hover{
  border-color:var(--teal);
  color:var(--teal) !important;
  transform:translateY(-3px);
}
.sas-social .elementor-social-icon i,
.sas-social .elementor-social-icon svg{ color:inherit !important; fill:currentColor; }

/* Quick links read as plain stacked links, nudging right on hover */
.sas-foot-links .elementor-icon-list-item{ display:block; }
.sas-foot-links .elementor-icon-list-item a{
  display:block; padding:7px 0;
  transition:color .25s ease, transform .25s ease;
}
.sas-foot-links .elementor-icon-list-item a:hover{ transform:translateX(3px); }
.sas-foot-links .elementor-icon-list-icon{ display:none; }

/* Row rhythm now comes entirely from the widget's own space_between:14
   setting (Elementor's native mechanism), not fought with padding here -
   its own more-specific `padding-block-end` rule was zeroing out any bottom
   padding set from here regardless. */
.sas-foot-contact .elementor-icon-list-item{ align-items:center; }

/* Elementor's Icon List "Text" typography group saves correctly (checked via
   get_post_meta - font_size:14.5 is really there) but never actually
   generates a font-size CSS rule for .elementor-icon-list-text - confirmed by
   reading the generated CSS file directly, same gap as the form button_width
   control. Set directly here instead, matching .foot-item{font-size:14.5px}
   in the reference. */
.sas-foot-contact .elementor-icon-list-text{ font-size:14.5px !important; }
.sas-foot-contact .elementor-icon-list-item:nth-child(2) .elementor-icon-list-text{ color:var(--periwinkle); }

/* The phone glyph (a diagonal handset) fills far less of its own bounding
   box than the pin/envelope beside it - confirmed by rendering all three at
   the same size: pin and envelope read as bold/filled, phone reads as thin
   and off-center even though its SVG box is pixel-identical to the others.
   This is inherent to that glyph (the reference's own phone icon is drawn at
   the same diagonal), not a positioning bug - compensating with a modest
   size bump so it reads as equal visual weight, a standard optical-sizing
   fix for icons of differing fill density. */
.sas-foot-contact .elementor-icon-list-item:nth-child(3) svg{ transform:scale(1.25); }

/* ============================================================
   Contact section - drifting particle field
   ============================================================ */
.sas-contact{ position:relative; isolation:isolate; }
.sas-contact::before{
  content:''; position:absolute; inset:0; z-index:0; pointer-events:none; opacity:.5;
  background-image:radial-gradient(rgba(124,147,255,0.35) 1px, transparent 1.6px);
  background-size:34px 34px;
}
.sas-contact > .e-con-inner{ position:relative; z-index:1; }

/* ============================================================
   Hero entrance - staggered fade-up on load, matching .hero-load
   ============================================================ */
.sas-load{ opacity:0; transform:translateY(24px); animation:sas-hero-fade-up .9s cubic-bezier(.2,.8,.2,1) forwards; }
.sas-load.l1{ animation-delay:.05s; }
.sas-load.l2{ animation-delay:.22s; }
.sas-load.l3{ animation-delay:.38s; }
.sas-load.l4{ animation-delay:.52s; }
@keyframes sas-hero-fade-up{ to{ opacity:1; transform:translateY(0); } }

/* ============================================================
   Hero H1 - name + tagline spans, matching site-src exactly
   ============================================================ */
.hero-name{ display:block; margin-bottom:14px; }
.hero-tagline{ display:block; font-size:0.62em; font-weight:500; color:var(--muted); line-height:1.3; }
.hero h1 em, #home h1 em{
  font-style:normal !important; font-weight:700;
  background:linear-gradient(120deg, var(--indigo), var(--periwinkle));
  -webkit-background-clip:text; background-clip:text; color:transparent;
  -webkit-text-fill-color:transparent;
}

/* ============================================================
   3D rotating drum - the real perspective cylinder, not a flip
   ============================================================ */
.sas-drum-viewport{
  position:relative; width:100%; max-width:540px; height:120px;
  perspective:1100px; margin-inline:auto;
  overflow:hidden; /* harmless belt-and-braces, but NOT what actually hides
                       the inactive faces - overflow:hidden on an element
                       with 3D-transformed preserve-3d descendants doesn't
                       reliably clip them in every browser. site.js drives
                       opacity/visibility per face directly instead, which
                       is what actually guarantees only one word shows. */
}
.sas-drum-track{
  position:absolute; inset:0; transform-style:preserve-3d;
  transition:transform .75s cubic-bezier(.4,.1,.2,1);
}
.sas-drum-track > .elementor-element{
  position:absolute; inset:0;
  display:flex; align-items:center; justify-content:flex-start;
  backface-visibility:hidden;
  background:linear-gradient(90deg, rgba(76,111,255,0.12), transparent);
  border-left:4px solid var(--indigo);
  padding-left:26px;
}
.sas-drum-track .elementor-heading-title{
  font-family:'Sora',sans-serif; font-size:clamp(34px,4.2vw,50px);
  color:var(--periwinkle); font-weight:600; line-height:1; text-align:left;
}
@media (max-width:900px){
  .sas-drum-viewport{ height:76px; }
  .sas-drum-track > .elementor-element{ padding-left:16px; border-left-width:3px; }
  .sas-drum-track .elementor-heading-title{ font-size:30px; }
}

/* Scroll indicator sits bottom-right in the hero, as in the source */
.sas-hero .sas-scroll-indicator{
  position:absolute; right:44px; bottom:44px; z-index:5;
}
@media (max-width:900px){
  .sas-hero .sas-scroll-indicator{ right:50%; transform:translateX(50%); bottom:24px; }
}

/* ============================================================
   Nav links - Elementor's OWN pointer-underline (`e--pointer-underline
   e--animation-slide`, set as this widget's Pointer/Animation in session 3)
   already renders the exact hover/active underline the reference uses,
   toggled via its native `.elementor-item-active` class - the scrollspy
   in site.js drives that class directly, so no duplicate ::after is added
   here (a second one would visibly double the line).
   ============================================================ */
.sas-nav .elementor-item:hover,
.sas-nav .elementor-item.elementor-item-active{ color:var(--text) !important; }

/* ============================================================
   Contact form - true floating labels, matching the reference's
   `.field.floating` pattern via :has() so it works regardless of
   whether Elementor renders the label before or after the input.
   ============================================================ */
.sas-form .elementor-field-group{ position:relative; }
.sas-form .elementor-field-type-text .elementor-field-textual,
.sas-form .elementor-field-type-email .elementor-field-textual,
.sas-form .elementor-field-type-tel .elementor-field-textual,
.sas-form .elementor-field-type-url .elementor-field-textual,
.sas-form .elementor-field-type-textarea .elementor-field-textual{
  padding:12px 14px !important;
}
.sas-form .elementor-field-label{
  position:static !important; top:auto !important; left:auto !important;
  font-size:13px !important; color:#B8C0E0 !important; font-weight:600 !important;
  text-transform:none !important; letter-spacing:normal !important;
  pointer-events:auto !important; margin:0 0 7px 0 !important;
  display:block !important;
}
.sas-form .elementor-field-group:has(.elementor-field-textual:focus) .elementor-field-label,
.sas-form .elementor-field-group:has(.elementor-field-textual:not(:placeholder-shown)) .elementor-field-label{
  position:static !important; top:auto !important; font-size:13px !important; color:#B8C0E0 !important;
}
/* niche + drive-link fields have unusually long labels ('Your project
   niche (e.g. Fashion, SaaS, Real Estate)', 'Insert your documents Drive
   link (optional)') that wrap to 2 lines at narrow widths - the shared
   floating-label rule above assumes a single line (fixed top:15px on a
   ~55px-tall field), so the wrapped second line spilled below the
   field's own border into whatever sits underneath it. Give just these
   two fields room for a 2-line label instead of shrinking/truncating the
   helpful example text. */
@media (max-width:480px){
  .sas-form .elementor-field-group-niche .elementor-field-textual,
  .sas-form .elementor-field-group-drive .elementor-field-textual{
    padding-top:30px !important; min-height:76px;
  }
  .sas-form .elementor-field-group-niche .elementor-field-label,
  .sas-form .elementor-field-group-drive .elementor-field-label{
    top:8px; line-height:1.3;
  }
  .sas-form .elementor-field-group-niche:has(.elementor-field-textual:focus) .elementor-field-label,
  .sas-form .elementor-field-group-niche:has(.elementor-field-textual:not(:placeholder-shown)) .elementor-field-label,
  .sas-form .elementor-field-group-drive:has(.elementor-field-textual:focus) .elementor-field-label,
  .sas-form .elementor-field-group-drive:has(.elementor-field-textual:not(:placeholder-shown)) .elementor-field-label{
    top:5px;
  }
}
/* Select/upload fields keep a static label above - a floating label over a
   dropdown or file picker has nothing meaningful to "float" against. The
   reference's own Drive-link field IS floating (type=url), so url is not
   excluded here. */
.sas-form .elementor-field-type-select .elementor-field-label,
.sas-form .elementor-field-type-upload .elementor-field-label{
  position:static !important; top:auto; left:auto; margin-bottom:7px !important;
}
.sas-form .elementor-field-type-url .elementor-field-textual{
  padding:20px 14px 8px !important;
}
.sas-form .elementor-field-type-select .elementor-field-textual{ padding:13px 14px !important; }

/* ============================================================
   About: real portrait with an overlaid name badge, replacing
   the placeholder brand card now that a real photo exists.
   ============================================================ */
.sas-about-portrait{
  position:relative; aspect-ratio:4/5; overflow:hidden; border-radius:6px;
  background:linear-gradient(150deg,#1b1e29,#0d0e14 70%);
  border:1px solid var(--border-soft);
  transition:transform .4s cubic-bezier(.2,.8,.2,1);
}
.sas-about-portrait::before{
  content:''; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:radial-gradient(circle at 30% 20%, rgba(76,111,255,0.2), transparent 55%);
}
.sas-about-portrait img{
  /* inset:0 alone stretches an absolutely positioned box via its offsets;
     adding width/height:100% on top of that hit a real 0-height bug in
     this engine (percentage-height-of-an-aspect-ratio-box is a known edge
     case) - inset alone sidesteps the percentage resolution entirely. */
  position:absolute; inset:0; object-fit:cover; object-position:top center;
  display:block; margin:0;
}
.sas-portrait-badge{
  /* Elementor's own Position:absolute control writes an inline-equivalent
     top:0 by default; without cancelling it, top:0 + bottom:22px stretches
     this to fill the whole portrait instead of sizing to its own content. */
  position:absolute !important; top:auto !important; z-index:2;
  bottom:22px; left:22px; right:22px; padding:16px 18px;
  background:rgba(10,11,16,0.75); -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  border:1px solid var(--border-soft); border-radius:4px;
}
.sas-portrait-badge .sas-badge-name .elementor-heading-title{
  font-family:'Sora',sans-serif; font-size:19px; font-weight:600; color:var(--text); margin-bottom:3px;
}
.sas-portrait-badge .sas-badge-role .elementor-heading-title{
  font-family:var(--mono); font-size:12.5px; color:var(--teal);
}

/* About copy: the widget holds three real <p> tags (not one merged block),
   so per-paragraph styling targets them directly - first bright + a
   decorative gradient drop-cap, the rest muted. Matches `.about-copy p`
   and `.about-copy p:first-of-type` in the reference exactly. */
.sas-about-copy p{ color:var(--muted); font-size:16px; line-height:1.85; margin-bottom:20px; }
.sas-about-copy p:first-of-type{
  color:var(--text); font-size:18.5px; font-family:'Sora',sans-serif; font-weight:400; line-height:1.6;
}
.sas-about-copy p:last-child{ margin-bottom:0; }
.sas-about-copy p:first-of-type::first-letter{
  font-size:3.6em; font-weight:800; line-height:.8; float:left;
  margin:0.06em 0.08em 0 0;
  background:linear-gradient(135deg,var(--indigo),var(--periwinkle));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}

/* cv-intro / contact-intro: same pattern - first <p> bright Sora, rest muted 15.5px */
.sas-cv-intro p, .sas-contact-intro p{ color:var(--muted); font-size:15.5px; line-height:1.85; margin-bottom:20px; }
.sas-cv-intro p:first-of-type, .sas-contact-intro p:first-of-type{
  color:var(--text); font-family:'Sora',sans-serif; font-size:17.5px; font-weight:400; line-height:1.6;
}
.sas-cv-intro p:last-child, .sas-contact-intro p:last-child{ margin-bottom:0; }

/* Contact intro: vertically centered in its column (matches the
   reference's .contact-intro{justify-content:center}), and sized up
   past the reference on the user's explicit request. Scoped to just
   .sas-contact-intro so .sas-cv-intro (Resume) is untouched. */
.elementor-element-cc21d74{ justify-content:center !important; }
.sas-contact-intro p{ font-size:17px !important; }
.sas-contact-intro p:first-of-type{ font-size:20px !important; }

/* Role tags: indigo-tinted, not teal - the reference reserves teal for
   stat chips and uses a softer indigo wash here. */
.sas-role-tag{
  display:inline-block; font-family:var(--mono); font-size:12.5px;
  color:var(--periwinkle); background:rgba(76,111,255,0.06);
  border:1px solid var(--border); border-radius:20px; padding:8px 14px;
}
.sas-role-tag .elementor-heading-title{
  border:none; border-radius:0; padding:0; background:none; display:inline;
}

/* Hero card avatar + live indicator */
.sas-hero-avatar-row{ display:flex; align-items:center; gap:10px; }
.sas-hero-avatar-row img{ width:30px; height:30px; border-radius:50%; object-fit:cover; display:block; }
.sas-hero-avatar-row .sas-hero-avatar-label .elementor-heading-title{
  font-family:var(--mono); font-size:12px; color:var(--muted);
}
.sas-live-dot{
  width:7px; height:7px; border-radius:50%; background:var(--teal);
  box-shadow:0 0 0 3px rgba(34,211,238,0.15);
}

/* Client logos: dashed border ring, per the reference (not solid) */
.sas-marquee .swiper-slide img{
  border-style:dashed !important;
}

/* Certificate badges: real badge artwork at its own size, not a filled icon tile */
#certifications .sas-card img{
  width:64px; height:64px; object-fit:contain; margin:0 auto;
}

/* Result screenshots: 16:9, matching `.result-img-wrap{aspect-ratio:16/9}` */
#portfolio .sas-shot img,
#portfolio .sas-shot:not(:has(img))::after{ aspect-ratio:16/9; }
/* Portfolio screenshots originally ranged 1.23-3.02 in aspect ratio,
   which no CSS crop/letterbox strategy could resolve cleanly for every
   image (full history of what was tried and why in CLAUDE.md, dated
   2026-09-15) - object-fit:cover cropped real content off two of them
   (a KPI tile, a stats sub-label), object-fit:contain left visible
   empty bars, and per-image aspect-ratio boxes broke row alignment.
   Fixed at the source instead: all 7 mismatched images (wp-image-
   21/23/28/20/22/24/25) were padded with white to an exact 16:10 canvas
   using GD (matches their own white dashboard backgrounds, so the
   padding is invisible - not a visible bar), then WP's registered sizes
   were regenerated from the padded originals. Every portfolio image is
   now genuinely 16:10, so the plain base .sas-shot img rule above needs
   no per-image exception at all - zero crop, zero bars, every row
   aligned, for every image including future uploads that also happen
   to arrive at 16:10 already. Only revisit this if a future upload has
   a very different ratio again. */

#portfolio .sas-card:hover{ border-color:var(--indigo); }

/* Service card: top accent bar sweeps in on hover, icon lifts */
#services .sas-card{ position:relative; }
#services .sas-card::after{
  content:''; position:absolute; top:0; left:0; width:100%; height:2px;
  background:linear-gradient(90deg,var(--indigo),var(--teal));
  transform:scaleX(0); transform-origin:left; transition:transform .4s ease;
}
#services .sas-card:hover::after{ transform:scaleX(1); }
#services .sas-card:hover{ background:var(--surface-2); }
#services .elementor-widget-theme-post-featured-image{ transition:transform .35s ease; }
#services .sas-card:hover .elementor-widget-theme-post-featured-image{ transform:translateY(-3px); }

/* Blog cards: radius6, 200px flush thumbnail, matching .blog-card/.blog-thumb */
#blog .sas-card{ border: 1px solid var(--border-soft); border-radius:6px !important; }
#blog .sas-shot img{ aspect-ratio:auto; height:200px; }
#blog .sas-card:hover{ background:var(--surface-2); border-color:var(--indigo); }

/* Resume "Core Skills" panel + skill boxes, matching .cv-panel/.skill-box exactly */
.sas-skill-box{
  background:var(--surface) !important; border-radius:6px !important;
}
.sas-skill-box:hover{ box-shadow:0 20px 40px -22px rgba(76,111,255,0.3); }
.sas-skill-box .sas-skill-pct .elementor-heading-title{
  font-family:var(--sans) !important; font-size:34px !important; font-weight:500 !important; color:var(--periwinkle) !important;
}
.sas-skill-box .sas-skill-name .elementor-heading-title{
  color:var(--text) !important; font-size:14.5px !important;
}
.sas-skill .elementor-progress-wrapper{ height:3px !important; border-radius:3px !important; background:rgba(255,255,255,0.08) !important; }
.sas-skill .elementor-progress-bar{ height:3px !important; border-radius:3px !important; }

/* ============================================================
   Services icons - true inline SVG (Fix 2, 2026-09-14)
   The Icon widget can't dynamic-bind selected_icon per Loop item,
   so this section is now 9 static cards, each with a real Icon
   widget holding a custom-uploaded SVG (currentColor stroke).
   ============================================================ */
.sas-card .svc-icon{
  width:42px; height:42px; color:#4C6FFF; fill:none !important;
  transition:color .3s ease, transform .35s ease;
}
.sas-card:hover .svc-icon{ color:#22D3EE; transform:translateY(-3px); }

/* ============================================================
   Header/footer logo - true inline SVG (Fix 3, 2026-09-14)
   Icon widget with a custom-uploaded SVG (attachments 100/101),
   matching the reference's own inline <svg class="logo-svg"> exactly.
   ============================================================ */
.sas-logo .elementor-icon{ display:inline-flex; }
.logo-svg{ height:42px !important; width:auto !important; display:block; }
.sas-logo-footer .logo-svg{ height:46px !important; }

/* ============================================================
   Reduced motion - honour the user's OS setting
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  .sas-reveal{ opacity:1 !important; transform:none !important; transition:none !important; }
  /* The hero must never stay invisible for someone who opted out of motion. */
  .sas-load{ opacity:1 !important; transform:none !important; animation:none !important; }
  .sas-drum-track{ transition:none !important; }
  .sas-form-wrap:focus-within::before{ animation:none; }
  .sas-form .elementor-button.sas-sent::after{ animation:none; }
  .elementor-loop-container > .e-loop-item{ animation:none !important; opacity:1 !important; transform:none !important; }
  .sas-hero-graph .sas-growth-line{ animation:none; stroke-dashoffset:0; }
  .sas-hero-graph .sas-growth-area{ animation:none; opacity:1; }
  .sas-scroll-indicator .sas-mouse::after{ animation:none; }
  .sas-cursor-dot,.sas-cursor-ring{ display:none !important; }
}

/* ============================================================
   HERO — custom-coded section (2026-09-15), rebuilt to match the
   supplied reference index.html verbatim (class names, structure and
   values), scoped with #home so it can't collide with anything else.
   Contact is back to native Elementor (its own sas-form-wrap rules,
   above, already handle its animation - untouched by this block).
   ============================================================ */
/* align-items:center (matching the reference exactly) plus min-height:100vh
   means on any viewport where the hero-grid's own content is shorter than
   the available height (150+110px padding subtracted from 100vh) - true on
   most common wide/short desktop resolutions, e.g. 1920x1080 - the extra
   space gets split above AND below the content by centering, showing as a
   large, unexplained-looking empty gap directly under the fixed header.
   Confirmed this isn't a live-site deviation: opening the user's own
   reference file standalone at 1920x1080 puts its H1 at the identical
   ~299px from top via the same centering math. Top-aligning instead keeps
   the visual distance from the header to the H1 fixed at padding-top
   (150px) on every viewport height, moving the leftover space below the
   content instead of splitting it above/below - eliminates the dead-
   looking gap without touching anything about the actual content or the
   150px clearance the fixed header needs. */
/* padding-top: user settled on a RESPONSIVE gap target this time - 60px
   on desktop, tapering to 20px on mobile/tablet - rather than one fixed
   value across every breakpoint. Desktop (this base rule, >900px):
   107px = header(79) + 60 - the 32px empirical H1 offset. Mobile/tablet
   tiers use 67px (see the two @media blocks below) for a 20px gap. */
/* min-height:100vh removed - with align-items:flex-start (top-aligned,
   from the earlier header-gap fix) any leftover space between 100vh and
   the actual content height now landed entirely BELOW the content
   instead of split top/bottom the way align-items:center used to do it -
   on a short-content/tall-viewport combo (e.g. 1920x1080) that was up to
   438px of dead space before the next section. Hero now sizes to its own
   content + padding, same as the mobile tiers already did. */
#home.hero{
  position:relative; display:flex; align-items:flex-start; padding:118px 40px 80px;
  background:var(--ink); overflow:hidden;
}

#home .reveal{ opacity:0; transform:translateY(28px); transition:opacity .8s cubic-bezier(.2,.8,.2,1), transform .8s cubic-bezier(.2,.8,.2,1); }
#home .reveal.in{ opacity:1; transform:translateY(0); }
@media (prefers-reduced-motion: reduce){ #home .reveal{ opacity:1; transform:none; transition:none; } }
#home .gradient-mesh{
  position:absolute; inset:-10%; z-index:0; pointer-events:none;
  background:
    radial-gradient(ellipse 800px 500px at 85% 15%, rgba(76,111,255,0.16), transparent 60%),
    radial-gradient(ellipse 700px 500px at 5% 90%, rgba(124,147,255,0.1), transparent 60%),
    radial-gradient(ellipse 600px 460px at 50% 50%, rgba(76,111,255,0.06), transparent 65%);
  background-size:140% 140%; will-change:transform;
  animation:heroMeshDrift 18s ease-in-out infinite alternate;
}
@keyframes heroMeshDrift{
  0%{ transform:translate3d(0,0,0); }
  100%{ transform:translate3d(15px,10px,0); }
}
@media (prefers-reduced-motion: reduce){ #home .gradient-mesh{ animation:none; } }
#home .cursor-glow{
  position:absolute; top:0; left:0; width:460px; height:460px; border-radius:50%;
  background:radial-gradient(circle, rgba(76,111,255,0.16), rgba(76,111,255,0.05) 45%, transparent 70%);
  transform:translate(-50%,-50%);
  pointer-events:none; z-index:1; mix-blend-mode:screen;
  opacity:0; transition:opacity .4s ease;
  will-change:transform;
}
#home.hero:hover .cursor-glow{ opacity:1; }
@media (hover:none){ #home .cursor-glow{ display:none; } }

#home .hero-load{ opacity:0; transform:translateY(24px); animation:heroFadeUp .9s cubic-bezier(.2,.8,.2,1) both; }
#home .hero-load.d1{ animation-delay:.05s; }
#home .hero-load.d2{ animation-delay:.22s; }
#home .hero-load.d3{ animation-delay:.38s; }
#home .hero-load.d4{ animation-delay:.52s; }
@keyframes heroFadeUp{ to{ opacity:1; transform:translateY(0); } }
@media (prefers-reduced-motion: reduce){ #home .hero-load{ opacity:1; transform:none; animation:none; } }

#home .scroll-indicator{
  position:absolute; right:44px; bottom:44px;
  display:flex; flex-direction:column; align-items:center; gap:12px; z-index:5;
  color:var(--muted); transition:opacity .4s ease, transform .4s ease;
  cursor:pointer;
}
#home .scroll-indicator span{
  font-family:var(--mono); font-size:10px; letter-spacing:0.2em; text-transform:uppercase;
  writing-mode:vertical-rl;
}
#home .scroll-ring{
  position:relative; width:52px; height:52px; border-radius:50%;
  border:1px solid rgba(124,147,255,0.35);
  display:flex; align-items:center; justify-content:center;
}
#home .scroll-ring::before{
  content:''; position:absolute; inset:-1px; border-radius:50%;
  border:1px solid transparent; border-top-color:var(--indigo);
  animation:heroRingSpin 3s linear infinite;
}
#home .scroll-dot{
  width:7px; height:7px; border-radius:50%; background:var(--indigo);
  box-shadow:0 0 14px 2px rgba(76,111,255,0.6);
  animation:heroDotPulse 1.8s ease infinite;
}
@keyframes heroRingSpin{ to{ transform:rotate(360deg); } }
@keyframes heroDotPulse{
  0%,100%{ transform:scale(1); opacity:1; }
  50%{ transform:scale(1.5); opacity:0.6; }
}
#home .scroll-indicator.hidden{ opacity:0; transform:translateY(10px); pointer-events:none; }
@media (prefers-reduced-motion: reduce){ #home .scroll-ring::before{animation:none;} #home .scroll-dot{animation:none;} }
@media (max-width:900px){ #home .scroll-indicator{ right:24px; bottom:28px; } #home .scroll-ring{ width:44px; height:44px; } }

#home .hero-skill-card{
  display:flex; flex-direction:column; justify-content:center; min-height:500px; padding:56px 48px;
}
#home .drum-viewport-inner{ display:flex; justify-content:center; padding:16px 0 10px; }
#home .skill-card-note{ font-size:15px; color:var(--muted); text-align:center; margin-top:24px; line-height:1.65; }
/* Vertical ticker (was a 3D rotateX drum - replaced per user's explicit
   choice from the 3-option preview). Same viewport footprint, same face
   type treatment (font, colors, border-left, background), same 2200ms
   step timing - only the motion mechanism changed, from 3D rotation to a
   plain translateY slide. This also permanently sidesteps the drum's
   proven geometric bug (a 6-face single-axis rotateX drum can't show only
   one face at a time via backface-visibility alone - 3 of 6 faces are
   always within +-90 deg of "front" and stay visible simultaneously,
   confirmed by reproducing it in the user's own reference file standalone)
   - overflow:hidden clipping a simple vertical offset has no equivalent
   failure mode. */
#home .drum-viewport{ position:relative; width:100%; max-width:540px; height:120px; overflow:hidden; }
#home .drum-track{ transition:transform .75s cubic-bezier(.4,.1,.2,1); will-change:transform; }
#home .drum-face{
  height:120px; display:flex; align-items:center; justify-content:center;
  font-family:var(--display); font-size:clamp(34px,4.2vw,50px); color:var(--periwinkle); font-weight:600;
  line-height:1; text-align:center;
  background:linear-gradient(90deg, rgba(76,111,255,0.12), transparent);
  border-left:4px solid var(--indigo); padding-left:26px;
}
@media (prefers-reduced-motion: reduce){ #home .drum-track{ transition:none; } }
@media (max-width:900px){ #home .hero-skill-card{ min-height:auto; padding:36px 26px; } #home .drum-viewport{ height:76px; } #home .drum-face{ height:76px; font-size:30px; padding-left:16px; border-left-width:3px; } }
#home .hero-graph{ position:absolute; inset:0; z-index:0; opacity:0.5; }

#home .hero-grid{
  max-width:1320px; margin:0 auto; padding:0; position:relative; z-index:2;
  display:grid; grid-template-columns:1.25fr 0.95fr; gap:70px; align-items:center; width:100%;
}
#home .hero-kicker{ font-family:var(--mono); font-size:13px; color:var(--teal); letter-spacing:0.15em; text-transform:uppercase; margin-bottom:26px; display:block; }
#home h1{ font-size:clamp(38px,4.6vw,60px); line-height:1.12; color:var(--text); margin-bottom:32px; }
#home .hero-name{ display:block; margin-bottom:14px; }
#home .hero-tagline{ display:block; font-size:0.62em; font-weight:500; color:var(--muted); line-height:1.3; }
#home h1 em{
  font-style:normal; font-weight:700;
  background:linear-gradient(120deg, var(--indigo), var(--periwinkle));
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
#home .hero-desc{ font-size:18px; color:var(--muted); max-width:640px; line-height:1.6; margin-bottom:36px; font-weight:400; }
#home .hero-desc strong{ color:var(--text); font-weight:700; }
#home .hero-desc .accent{ color:var(--periwinkle); font-weight:700; }
#home .hero-ctas{ display:flex; gap:16px; flex-wrap:wrap; margin-bottom:56px; }
/* At narrow widths the 3 items (two ~120-165px buttons + a ~120px text
   link) don't fit two-per-row either, so flex-wrap drops each onto its
   own line - three same-height pills stacked with gaps reads as messy,
   not intentional. Stack Hire Me/View Portfolio full-width (a standard,
   clean mobile CTA pattern) and shrink Contact Me back down to a compact
   text link so it reads as a third, lighter-weight action rather than a
   3rd same-size button. */
@media (min-width:850px) and (max-width:1199px){
  /* Two-column hero: viewport-scaled name font outgrows the shrinking
     left column in this range, wrapping to 2 lines. Tie it to the
     narrower column width instead. */
  #home .hero-name{ font-size:4.2vw; }
}
@media (max-width:520px){
  #home .hero-name{ font-size:clamp(24px,7.8vw,34px); }
  #home .hero-ctas{ display:flex; flex-direction:row; flex-wrap:nowrap; align-items:center; gap:8px; margin-bottom:30px; width:100%; }
  #home .hero-ctas .btn{ margin:0; flex-shrink:0; }
  #home .hero-ctas .btn-primary, #home .hero-ctas .btn-outline{ width:auto; padding:8px 14px; font-size:11.5px; font-weight:600; justify-content:center; text-align:center; white-space:nowrap; border-radius:100px; }
  #home .hero-ctas .btn-ghost{ width:auto; padding:8px 4px; font-size:11.5px; font-weight:500; white-space:nowrap; display:inline-flex; align-items:center; gap:3px; }
}
#home .btn{
  display:inline-flex; align-items:center; gap:8px; padding:13px 26px; font-size:13px; font-weight:600;
  border-radius:100px; letter-spacing:0.02em; transition:all .35s cubic-bezier(.2,.8,.2,1); cursor:pointer; border:1px solid transparent;
}
/* Tablet: a step down from desktop, a step up from the mobile size below -
   keeps the minimal look consistent instead of jumping straight from the
   full desktop size to the mobile size at the 520px breakpoint. */
@media (max-width:900px) and (min-width:521px){
  #home .hero-ctas .btn-primary, #home .hero-ctas .btn-outline{ padding:12px 24px; font-size:13px; }
  #home .hero-ctas .btn-ghost{ font-size:13px; }
}
#home .btn-primary{
  background:linear-gradient(135deg, var(--indigo), #7B93FF); color:#0A0B10; font-weight:700;
  box-shadow:0 10px 26px -10px rgba(76,111,255,0.55);
}
#home .btn-primary:hover{
  background:linear-gradient(135deg, var(--periwinkle), var(--indigo));
  transform:translateY(-3px) scale(1.02); box-shadow:0 18px 38px -10px rgba(76,111,255,0.6);
}
#home .btn-outline{ border-color:rgba(255,255,255,0.22); color:var(--text); background:rgba(255,255,255,0.02); }
#home .btn-outline:hover{ border-color:var(--teal); color:var(--teal); background:rgba(34,211,238,0.08); transform:translateY(-3px); }
#home .btn-ghost{ color:var(--muted); border-color:transparent; padding-left:6px; padding-right:6px; }
#home .btn-ghost:hover{ color:var(--periwinkle); }
#home .btn-arrow{ display:inline-block; transition:transform .3s cubic-bezier(.2,.8,.2,1); }
#home .btn:hover .btn-arrow{ transform:translateX(5px); }

#home .hero-card{
  background:linear-gradient(160deg, rgba(255,255,255,0.045), rgba(255,255,255,0.015));
  border:1px solid var(--border-soft); border-radius:6px; padding:34px;
  backdrop-filter:blur(20px);
  box-shadow:0 30px 60px -20px rgba(0,0,0,0.5);
}
#home .hero-card-head{ display:flex; justify-content:space-between; align-items:center; margin-bottom:22px; padding-bottom:18px; border-bottom:1px solid var(--border-soft); }
/* Color matched to the site's eyebrow labels (.sas-eyebrow, e.g. "About",
   "Insights") per explicit request - was var(--muted), now var(--teal). */
#home .hero-card-head span{ font-family:var(--mono); font-size:12px; color:var(--teal); text-transform:uppercase; letter-spacing:0.1em; }
#home .hero-card-brand{ display:flex; align-items:center; gap:10px; }
#home /* Reverted back to the reference's original 30px - a 44px version was
   tried per explicit request to make the photo easier to see, but the
   resulting taller card read as "broken" size, so this is back to
   matching the reference exactly. */
.hero-avatar{
  width:48px; height:48px; border-radius:50%; object-fit:cover;
  border:1.5px solid var(--border); flex-shrink:0;
}
#home .live-dot{ width:7px; height:7px; border-radius:50%; background:var(--teal); box-shadow:0 0 0 0 rgba(124,147,255,0.6); animation:heroLiveDotPulse 2s infinite; }
@keyframes heroLiveDotPulse{
  0%{ box-shadow:0 0 0 0 rgba(124,147,255,0.5); }
  70%{ box-shadow:0 0 0 8px rgba(124,147,255,0); }
  100%{ box-shadow:0 0 0 0 rgba(124,147,255,0); }
}
@media (prefers-reduced-motion: reduce){ #home .live-dot{ animation:none; } }

@media (max-width:900px){
  #home.hero{ min-height:auto; padding:100px 24px 60px; }
  #home .hero-grid{ grid-template-columns:1fr; gap:44px; }
}
@media (max-width:520px){
  #home.hero{ padding:100px 16px 48px; }
}
/* ============================================================
   BLOG (page 16) - category pill nav
   ============================================================ */
.sas-blog-pillnav .sas-blog-pill .elementor-button{
  font-family:var(--mono); font-size:12.5px; font-weight:500; letter-spacing:0.02em;
  padding:9px 16px; border-radius:20px; border:1px solid var(--border);
  background:rgba(76,111,255,0.06); color:var(--periwinkle);
  transition:background .25s ease, border-color .25s ease, color .25s ease;
}
.sas-blog-pillnav .sas-blog-pill .elementor-button:hover{
  background:rgba(76,111,255,0.14); border-color:var(--indigo); color:var(--text);
}
.sas-blog-pillnav .sas-blog-pill.sas-pill-active .elementor-button{
  background:linear-gradient(135deg, var(--indigo), #7B93FF); border-color:transparent; color:#0A0B10; font-weight:700;
}
/* Elementor Pro's native Taxonomy Filter widget, replacing the old static
   link-button pills (which pointed at /blogs/<slug>/ URLs that never matched
   the real /category/<slug>/ archive links and had zero filtering wired to
   the Loop Grid). This does real AJAX filtering keyed to the Loop Grid's
   element ID, so it needs its own styling to match the old pill look since
   it renders plain <search>/<button class="e-filter-item"> markup. */
.sas-blog-filterbar{ display:flex; flex-wrap:wrap; gap:10px; justify-content:center; }
.sas-blog-filterbar .e-filter{ display:flex !important; flex-wrap:wrap !important; gap:10px !important; justify-content:center !important; width:100% !important; }
.sas-blog-filterbar .e-filter-item[data-filter="__all"]{ order:-1 !important; }
.sas-blog-filterbar .e-filter-item{
  font-family:var(--mono); font-size:12.5px; font-weight:500; letter-spacing:0.02em;
  padding:9px 16px; border-radius:20px; border:1px solid var(--border);
  background:rgba(76,111,255,0.06); color:var(--periwinkle);
  cursor:pointer; transition:background .25s ease, border-color .25s ease, color .25s ease;
}
.sas-blog-filterbar .e-filter-item:hover{
  background:rgba(76,111,255,0.14); border-color:var(--indigo); color:var(--text);
}
.sas-blog-filterbar .e-filter-item[aria-pressed="true"]{
  background:linear-gradient(135deg, var(--indigo), #7B93FF); border-color:transparent; color:#0A0B10; font-weight:700;
}
/* Hide WordPress's built-in "Uncategorized" fallback bucket from the filter
   bar - it's not one of the 9 real service categories, showing it would just
   confuse visitors. show_empty_items is on so every real category appears
   even before it has a post yet; this is the one term that should never show. */
.sas-blog-filterbar .e-filter-item[data-filter="uncategorized"]{ display:none; }
/* The filter bar's <search> element had no width constraint, so as a nested
   flex container it sized itself to fit ALL pills in one unbroken row
   (its max-content width) instead of respecting the section's actual width -
   flex-wrap:wrap never kicked in because there was nothing to wrap AGAINST,
   so it just overflowed off both edges of the screen. Switching to a fixed-
   row-count CSS grid (2 rows desktop, 4 rows mobile) instead of relying on
   flex-wrap gives a predictable, clean layout instead of an unpredictable
   number of wrapped rows, with horizontal scroll as a graceful fallback if
   a row still doesn't fully fit. */
.sas-blog-filterbar{ width:100%; }
.sas-blog-filterbar search.e-filter{
  display:flex !important;
  flex-wrap:wrap !important;
  justify-content:center !important;
  gap:10px !important;
  width:100% !important;
  padding-bottom:4px;
}
@media (max-width:767px){
  .sas-blog-filterbar search.e-filter{
    display:flex !important;
    flex-wrap:wrap !important;
    gap:6px !important;
    justify-content:center !important;
  }
  .sas-blog-filterbar .e-filter-item{
    white-space:nowrap;
    text-align:center;
    font-size:11px;
    line-height:1.2;
    padding:6px 12px;
    min-height:0;
    border-radius:999px;
    display:inline-flex;
    align-items:center;
    justify-content:center;
  }
}
/* ============================================================
   Modern Blog Post template - 3-column layout (sticky TOC / content /
   sticky "Explore Our Posts" sidebar), following the same structural
   pattern as the realistic3d.co reference post template but using this
   site's own tokens (indigo/teal, Sora/Inter) instead of copying its
   gold/Khand skin. Scoped entirely under .modern-post so it can never
   leak into any other page.
   ============================================================ */
.modern-post{
  --mp-accent:var(--indigo); --mp-accent-hover:var(--periwinkle);
  --mp-hairline:var(--border-soft); --mp-radius:10px; --mp-radius-sm:6px;
  --mp-shadow:0 8px 24px rgba(0,0,0,0.4); --mp-speed:150ms; --mp-scroll-offset:140px;
  background:var(--ink); color:var(--text); font-family:var(--sans);
  font-size:16px; line-height:1.75;
}
.modern-post *,.modern-post *::before,.modern-post *::after{ box-sizing:border-box; }
.modern-post img{ max-width:100%; height:auto; }

.modern-post .mp-layout{
  display:grid; grid-template-columns:260px minmax(0,1fr) 300px; gap:44px;
  align-items:start; max-width:1360px; margin:0 auto; padding:156px 24px 96px;
}
.modern-post .mp-layout--no-right{ grid-template-columns:260px minmax(0,1fr); }

/* Table of contents */
.modern-post .mp-toc-col{ position:sticky; top:calc(var(--mp-scroll-offset) + 16px); align-self:start; }
.modern-post .mp-toc-sticky{ display:flex; flex-direction:column; gap:20px; }
.modern-post .mp-toc{
  background:var(--surface); border:1px solid var(--mp-hairline);
  border-radius:var(--mp-radius); box-shadow:var(--mp-shadow); overflow:hidden;
}
.modern-post .mp-toc__toggle{
  display:flex; align-items:center; justify-content:space-between; width:100%;
  padding:18px 20px; margin:0; background:transparent; border:0; cursor:pointer;
  text-align:left; color:var(--text); font-family:var(--display); font-weight:600;
  font-size:1.25rem; letter-spacing:.02em; text-transform:uppercase;
}
.modern-post .mp-toc__heading{ position:relative; padding-left:16px; }
.modern-post .mp-toc__heading::before{
  content:''; position:absolute; left:0; top:50%; transform:translateY(-50%);
  width:4px; height:1.1em; background:var(--mp-accent); border-radius:2px;
}
.modern-post .mp-toc__chevron{
  display:none; width:10px; height:10px; border-right:2px solid var(--muted);
  border-bottom:2px solid var(--muted); transform:rotate(45deg);
  transition:transform var(--mp-speed) ease;
}
.modern-post .mp-toc__panel{ padding:4px 20px 20px; }
.modern-post .mp-toc__track{ position:relative; }
.modern-post .mp-toc__list{ list-style:none; margin:0; padding:0 0 0 16px; border-left:1px solid var(--mp-hairline); }
.modern-post .mp-toc__list .mp-toc__list{ border-left:0; padding-left:14px; }
.modern-post .mp-toc__item{ margin:0; }
.modern-post .mp-toc__link{ display:block; padding:7px 0; color:var(--muted); font-size:14px; line-height:1.4; transition:color var(--mp-speed) ease; }
.modern-post .mp-toc__link--h3{ font-size:13px; padding-left:12px; }
.modern-post .mp-toc__link:hover,.modern-post .mp-toc__link:focus{ color:var(--text); }
.modern-post .mp-toc__link.is-active{ color:var(--mp-accent); font-weight:500; }

/* Content column */
.modern-post .mp-content{ min-width:0; }
.modern-post .mp-post-header{ margin-bottom:32px; }
.modern-post .mp-title{
  font-family:var(--display); font-weight:600; font-size:clamp(2.2rem, 4.5vw, 3.2rem);
  line-height:1.1; letter-spacing:.005em; color:var(--text); margin:0 0 20px;
}
.modern-post .mp-title::after{ content:''; display:block; width:64px; height:3px; margin-top:20px; background:var(--mp-accent); border-radius:2px; }
.modern-post .mp-meta{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; color:var(--muted); font-size:.9rem; letter-spacing:.01em; }
.modern-post .mp-meta__sep{ color:var(--mp-accent); }
.modern-post .mp-meta a{ color:var(--muted); }
.modern-post .mp-meta a:hover,.modern-post .mp-meta a:focus{ color:var(--mp-accent-hover); }
.modern-post .mp-featured{ margin:0 0 36px; }
.modern-post .mp-featured__img{ display:block; width:100%; height:auto; border-radius:var(--mp-radius); border:1px solid var(--mp-hairline); }
.modern-post .mp-entry{ color:var(--text); font-size:16px; line-height:1.75; }
.modern-post .mp-entry>*{ margin-top:0; margin-bottom:1.4em; }
.modern-post .mp-entry h2,.modern-post .mp-entry h3,.modern-post .mp-entry h4{
  font-family:var(--display); font-weight:600; color:var(--text); line-height:1.15;
  scroll-margin-top:calc(var(--mp-scroll-offset) + 20px);
}
.modern-post .mp-entry h2{ font-size:1.8rem; margin-top:2em; padding-bottom:.3em; border-bottom:1px solid var(--mp-hairline); }
.modern-post .mp-entry h3{ font-size:1.35rem; margin-top:1.6em; color:var(--mp-accent); }
.modern-post .mp-entry h4{ font-size:1.15rem; margin-top:1.4em; }
.modern-post .mp-entry a{ color:var(--periwinkle); text-decoration:underline; text-decoration-color:var(--mp-hairline); text-underline-offset:3px; transition:color var(--mp-speed) ease,text-decoration-color var(--mp-speed) ease; }
.modern-post .mp-entry a:hover,.modern-post .mp-entry a:focus{ text-decoration-color:var(--mp-accent-hover); }
.modern-post .mp-entry img{ border-radius:var(--mp-radius-sm); }
.modern-post .mp-entry blockquote{ margin:1.8em 0; padding:4px 0 4px 24px; border-left:3px solid var(--mp-accent); color:var(--text); font-size:1.1rem; font-style:italic; }
.modern-post .mp-entry ul,.modern-post .mp-entry ol{ padding-left:1.4em; }
.modern-post .mp-entry li{ margin-bottom:.5em; }
.modern-post .mp-entry code{ font-family:var(--mono); font-size:.9em; background:var(--surface-2); border:1px solid var(--mp-hairline); border-radius:var(--mp-radius-sm); padding:.1em .4em; }
.modern-post .mp-entry pre{ background:var(--surface); border:1px solid var(--mp-hairline); border-radius:var(--mp-radius); padding:18px 20px; overflow-x:auto; }
.modern-post .mp-entry pre code{ background:none; border:0; padding:0; }
.modern-post .mp-entry table{ width:100%; border-collapse:collapse; display:block; overflow-x:auto; }
.modern-post .mp-entry th,.modern-post .mp-entry td{ border:1px solid var(--mp-hairline); padding:10px 14px; text-align:left; }
.modern-post .mp-entry th{ background:var(--surface-2); font-family:var(--display); font-weight:500; }

.modern-post .mp-author-box{ margin-top:48px; }
.modern-post .mp-post-nav{ display:grid; grid-template-columns:1fr 1fr; gap:20px; margin-top:56px; }
.modern-post .mp-post-nav__cell{ display:flex; flex-direction:column; gap:8px; }
.modern-post .mp-post-nav__cell:empty{ visibility:hidden; }
.modern-post .mp-post-nav__next{ text-align:right; align-items:flex-end; }
.modern-post .mp-post-nav__label{ font-family:var(--sans); font-size:.72rem; font-weight:500; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
.modern-post .mp-post-nav a{ color:var(--text); font-family:var(--display); font-weight:600; font-size:1.05rem; }
.modern-post .mp-post-nav a:hover,.modern-post .mp-post-nav a:focus{ color:var(--mp-accent); }

/* Sidebar */
.modern-post .mp-side-col{ display:flex; flex-direction:column; gap:24px; position:sticky; top:calc(var(--mp-scroll-offset) + 56px); }
.modern-post .mp-sidebar{ background:var(--surface); border:1px solid var(--mp-hairline); border-radius:var(--mp-radius); box-shadow:var(--mp-shadow); padding:22px; font-size:14px; line-height:1.6; }
.modern-post .mp-widget-title{ margin:0 0 14px; font-family:var(--display); font-weight:600; font-size:1.2rem; letter-spacing:.02em; color:var(--text); padding-bottom:12px; border-bottom:1px solid var(--mp-hairline); }
.modern-post .mp-widget ul{ list-style:none; margin:0; padding:0; }
.modern-post .mp-widget li{ padding:10px 0; border-bottom:1px solid var(--mp-hairline); }
.modern-post .mp-widget li:last-child{ border-bottom:0; }
.modern-post .mp-widget a{ color:var(--text); font-size:14px; line-height:1.4; }
.modern-post .mp-widget-item{ display:flex; align-items:flex-start; gap:12px; }
.modern-post .mp-widget-thumb{ flex:0 0 auto; width:64px; height:64px; border-radius:var(--mp-radius-sm); overflow:hidden; background:var(--surface-2); }
.modern-post .mp-widget-thumb img{ width:100%; height:100%; object-fit:cover; display:block; border-radius:0; }
.modern-post .mp-widget-item-title{ flex:1 1 auto; padding-top:2px; }
.modern-post .mp-widget a:hover,.modern-post .mp-widget a:focus{ color:var(--mp-accent-hover); }

.modern-post .search-form{ display:flex; width:100%; margin:0; }
.modern-post .search-form label{ flex:1 1 auto; min-width:0; }
.modern-post .search-form .screen-reader-text{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0,0,0,0); }
.modern-post .search-field{
  flex:1 1 auto; min-width:0; width:100%; padding:11px 14px; color:var(--text);
  background:var(--surface-2); border:1px solid var(--mp-hairline); border-right:0;
  border-radius:var(--mp-radius-sm) 0 0 var(--mp-radius-sm); font-family:var(--sans);
  font-size:14px; line-height:1.4; outline:none; transition:border-color var(--mp-speed) ease,box-shadow var(--mp-speed) ease;
}
.modern-post .search-field::placeholder{ color:var(--muted); }
.modern-post .search-field:focus{ border-color:var(--mp-accent); box-shadow:0 0 0 2px rgba(76,111,255,0.25); }
.modern-post .search-submit{
  flex:0 0 auto; margin:0; padding:11px 18px; color:#0A0B10; background:linear-gradient(135deg, var(--indigo), #7B93FF);
  border:none; border-radius:0 var(--mp-radius-sm) var(--mp-radius-sm) 0;
  font-family:var(--sans); font-weight:700; font-size:14px; line-height:1.4; cursor:pointer;
  transition:background var(--mp-speed) ease,box-shadow var(--mp-speed) ease;
}
.modern-post .search-submit:hover,.modern-post .search-submit:focus{ background:var(--mp-accent-hover); border-color:var(--mp-accent-hover); color:#080A14; }

/* Comments - standard WP core classes, styled to match */
.modern-post .mp-comments{ margin-top:56px; }
.modern-post .comments-title,.modern-post .comment-reply-title{
  font-family:var(--display); font-weight:600; font-size:1.5rem; color:var(--text);
  margin:0 0 24px; padding-left:16px; position:relative;
}
.modern-post .comments-title::before,.modern-post .comment-reply-title::before{
  content:''; position:absolute; left:0; top:.15em; width:4px; height:1.1em;
  background:var(--mp-accent); border-radius:2px;
}
.modern-post .comment-list{ list-style:none; margin:0 0 40px; padding:0; }
.modern-post .comment-list ol.children{ list-style:none; margin:0; padding-left:28px; }
.modern-post .comment-body{ padding:20px 0; border-bottom:1px solid var(--mp-hairline); }
.modern-post .comment-author{ display:flex; align-items:center; gap:10px; margin-bottom:6px; }
.modern-post .comment-author .avatar{ border-radius:50%; }
.modern-post .comment-author .fn{ font-family:var(--display); font-weight:600; font-style:normal; color:var(--text); }
.modern-post .comment-author .says{ display:none; }
.modern-post .comment-metadata,.modern-post .comment-metadata a{ font-size:.8rem; color:var(--muted); }
.modern-post .comment-content{ color:var(--text); font-size:16px; line-height:1.7; }
.modern-post .reply a,.modern-post .comment-reply-link{ display:inline-block; margin-top:8px; font-size:.8rem; font-weight:500; letter-spacing:.04em; text-transform:uppercase; color:var(--mp-accent); }
.modern-post .comment-respond{ background:var(--surface); border:1px solid var(--mp-hairline); border-radius:var(--mp-radius); padding:26px 28px; }
.modern-post .comment-form{ display:flex; flex-direction:column; gap:16px; }
.modern-post .comment-form .comment-notes,.modern-post .comment-form .logged-in-as{ font-size:.85rem; color:var(--muted); margin:0; }
.modern-post .comment-form label{ display:block; margin-bottom:6px; font-size:.85rem; color:var(--muted); }
.modern-post .comment-form input[type="text"],.modern-post .comment-form input[type="email"],.modern-post .comment-form input[type="url"],.modern-post .comment-form textarea{
  width:100%; padding:11px 14px; color:var(--text); background:var(--surface-2);
  border:1px solid var(--mp-hairline); border-radius:var(--mp-radius-sm); font-family:var(--sans);
  font-size:15px; line-height:1.5; outline:none; transition:border-color var(--mp-speed) ease,box-shadow var(--mp-speed) ease;
}
.modern-post .comment-form input:focus,.modern-post .comment-form textarea:focus{ border-color:var(--mp-accent); box-shadow:0 0 0 2px rgba(76,111,255,0.25); }
.modern-post .comment-form .form-submit{ margin:0; }
.modern-post .form-submit .submit{
  padding:11px 22px; color:#0A0B10; background:linear-gradient(135deg, var(--indigo), #7B93FF); border:none;
  border-radius:8px; font-family:var(--sans); font-weight:700; font-size:14px;
  letter-spacing:.02em; cursor:pointer; box-shadow:0 10px 26px -10px rgba(76,111,255,0.65); transition:transform .3s ease,box-shadow .3s ease,background .3s ease;
}
.modern-post .form-submit .submit:hover,.modern-post .form-submit .submit:focus{ background:var(--mp-accent-hover); border-color:var(--mp-accent-hover); }
.modern-post .no-comments{ color:var(--muted); font-style:italic; }

/* Responsive: single column, TOC collapses to an accordion */
@media (max-width:1440px){
  .modern-post .mp-layout,.modern-post .mp-layout--no-right{ padding:130px 40px 96px; }
}
@media (max-width:1024px){
  .modern-post .mp-layout,.modern-post .mp-layout--no-right{ display:flex; flex-direction:column; align-items:stretch; gap:32px; padding:130px 30px 72px; }
  .modern-post .mp-toc-col,.modern-post .mp-toc-sticky,.modern-post .mp-side-col{ display:contents; }
  .modern-post .mp-toc{ order:1; }
  .modern-post .mp-content{ order:2; }
  .modern-post .mp-sidebar{ order:3; }
  .modern-post .mp-toc-col{ position:static; }
  .modern-post .mp-side-col{ position:static; }
  .modern-post .mp-toc__chevron{ display:block; }
  .modern-post .mp-toc__toggle[aria-expanded="true"] .mp-toc__chevron{ transform:rotate(-135deg); }
  .modern-post .mp-toc__toggle[aria-expanded="false"]+.mp-toc__panel{ display:none; }
}
@media (max-width:767px){
  .modern-post .mp-layout,.modern-post .mp-layout--no-right{ padding:120px 20px 64px; }
  .modern-post .mp-post-nav{ grid-template-columns:1fr; }
  .modern-post .mp-post-nav__next{ text-align:left; align-items:flex-start; }
}
@media (max-width:560px){
  .modern-post .mp-entry h2{ font-size:1.5rem; }
  .modern-post .mp-entry h3{ font-size:1.25rem; }
}
@media (prefers-reduced-motion:reduce){
  .modern-post *,.modern-post *::before,.modern-post *::after{ transition-duration:.01ms!important; animation-duration:.01ms!important; scroll-behavior:auto!important; }
}
/* ============================================================
   Custom select dropdown for the Contact form's "Service needed" and
   "Estimated budget" fields. Native <select> open-list styling is
   controlled by the OS/browser (Android's dark system picker, iOS's
   wheel, desktop Chrome's own popup) and cannot be restyled with CSS -
   the closed state already matched the theme, but the OPEN list never
   could. initCustomSelects() in site.js builds this markup around each
   select and keeps the original <select> in the DOM (visually hidden,
   not disabled) purely so native form submission still reads its value
   - all the real interaction happens on the custom button/panel.
   ============================================================ */
.sas-form .elementor-select-wrapper{ position:relative; width:100%; }
.sas-form .elementor-select-wrapper select.elementor-field-textual{
  position:absolute; opacity:0; pointer-events:none;
  width:1px; height:1px; padding:0 !important; border:0 !important; margin:0;
}
.sas-form .sas-select{ position:relative; width:100%; }
.sas-form .sas-select__button{
  width:100%; display:flex; align-items:center; justify-content:space-between; gap:10px;
  background:var(--surface-2) !important; border:1px solid var(--border-soft) !important;
  border-radius:3px !important; color:var(--text); padding:13px 14px;
  font-family:var(--sans); font-size:14.5px; line-height:1.4; cursor:pointer; text-align:left;
  transition:border-color .3s ease, box-shadow .3s ease, background .3s ease;
}
.sas-form .sas-select__button:hover{ border-color:var(--indigo) !important; }
.sas-form .sas-select.is-open .sas-select__button{
  border-color:var(--indigo) !important; box-shadow:0 0 0 3px rgba(76,111,255,0.16); background:#19203c !important;
}
.sas-form .sas-select__label{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sas-form .sas-select__chevron{
  width:9px; height:9px; border-right:2px solid var(--muted); border-bottom:2px solid var(--muted);
  transform:rotate(45deg); transition:transform .25s ease; flex:0 0 auto; margin-top:-3px;
}
.sas-form .sas-select.is-open .sas-select__chevron{ transform:rotate(-135deg); margin-top:3px; }
.sas-form .sas-select__panel{
  position:absolute; left:0; right:0; top:calc(100% + 6px); z-index:50;
  background:var(--surface-2); border:1px solid var(--border-soft); border-radius:6px;
  box-shadow:0 20px 40px -12px rgba(0,0,0,0.65); overflow-y:auto; max-height:260px;
  opacity:0; visibility:hidden; transform:translateY(-6px);
  transition:opacity .2s ease, transform .2s ease, visibility 0s linear .2s;
}
.sas-form .sas-select.is-open .sas-select__panel{
  opacity:1; visibility:visible; transform:translateY(0);
  transition:opacity .2s ease, transform .2s ease;
}
.sas-form .sas-select__option{
  padding:11px 14px; font-size:14.5px; color:var(--text); cursor:pointer;
  transition:background .15s ease, color .15s ease;
}
.sas-form .sas-select__option + .sas-select__option{ border-top:1px solid var(--border-soft); }
.sas-form .sas-select__option:hover,
.sas-form .sas-select__option.is-highlighted{ background:rgba(76,111,255,0.14); color:var(--periwinkle); }
.sas-form .sas-select__option.is-selected{ color:var(--indigo); font-weight:600; }

/* ============================================================
   Legal pages (Privacy Policy, etc.) - plain text-editor content
   ============================================================ */
.sas-legal-body{ color:var(--muted); font-size:15px; line-height:1.75; max-width:100%; }
.sas-legal-body h2{ color:var(--text); font-family:var(--display); font-size:22px; font-weight:700; margin:36px 0 12px; }
.sas-legal-body h2:first-child{ margin-top:0; }
.sas-legal-body p{ margin:0 0 16px; }
.sas-legal-body ul{ margin:0 0 16px; padding-left:20px; }
.sas-legal-body li{ margin-bottom:8px; }
.sas-legal-body a{ color:var(--teal); text-decoration:underline; text-underline-offset:2px; }
.sas-legal-body a:hover{ color:var(--periwinkle); }
.sas-legal-body strong{ color:var(--text); }
.sas-legal-body em{ color:var(--muted-2); font-style:italic; }

/* ============================================================
   Free Audit popup (Elementor Pro popup, id set at creation)
   ============================================================ */
.sas-popup-icon{
  width:52px; height:52px; border-radius:14px; margin:0 auto 18px;
  background:linear-gradient(135deg, var(--indigo), var(--teal));
  display:flex; align-items:center; justify-content:center;
}
.sas-popup-icon svg{ width:26px; height:26px; }
.sas-popup-eyebrow .elementor-heading-title{
  font-family:var(--mono) !important; font-size:12px !important; font-weight:700 !important; letter-spacing:0.14em;
  text-transform:uppercase; color:var(--teal) !important; text-align:center; margin:0 0 10px;
}
.sas-popup-title .elementor-heading-title{
  font-family:var(--display) !important; font-size:26px !important; font-weight:800 !important; color:var(--text) !important;
  text-align:center; line-height:1.28; margin:0 0 12px;
}
.sas-popup-desc{
  font-size:15px; line-height:1.65; text-align:center; margin:0 0 26px;
  max-width:380px; margin-left:auto; margin-right:auto;
}
.sas-popup-desc p{ color:var(--muted) !important; }
.sas-popup-cta{ display:flex; justify-content:center; }
.sas-popup-cta .elementor-button{
  display:inline-flex; align-items:center; gap:8px; padding:14px 30px;
  font-family:var(--sans); font-size:14px; font-weight:700; letter-spacing:0.02em;
  border-radius:100px; color:#0A0B10 !important;
  background:linear-gradient(135deg, var(--indigo), #7B93FF);
  box-shadow:0 14px 30px -10px rgba(76,111,255,0.55);
  transition:transform .3s cubic-bezier(.2,.8,.2,1), box-shadow .3s ease;
}
.sas-popup-cta .elementor-button:hover{ transform:translateY(-3px); box-shadow:0 18px 36px -10px rgba(76,111,255,0.65); }
.sas-popup-note{ font-size:12px; color:var(--muted-2); text-align:center; margin:14px 0 0; }
@media (max-width:520px){
  .sas-popup-title{ font-size:22px; }
  .sas-popup-desc{ font-size:14px; }
}
.elementor-popup-modal .dialog-message{ max-height:92vh; overflow-y:auto; }
.sas-popup-form .elementor-field-group{ margin-bottom:0; }
.sas-popup-form .elementor-field-textual{ font-family:var(--sans); font-size:14px !important; }
.sas-popup-form .elementor-field-textual:focus{ border-color:var(--indigo) !important; outline:none; box-shadow:0 0 0 3px rgba(76,111,255,0.15); }
.sas-popup-form .elementor-field-label{ font-family:var(--sans); font-size:13px !important; font-weight:600; }
.sas-popup-form{ width:100%; margin-top:4px; }
/* Match the hero's "Hire Me" primary button exactly, instead of the flat
   solid color Elementor's own form button style control produces. */
.sas-popup-form .elementor-button{
  background:linear-gradient(135deg, var(--indigo), #7B93FF) !important;
  color:#0A0B10 !important; font-weight:700 !important;
  box-shadow:0 10px 26px -10px rgba(76,111,255,0.55);
  transition:transform .3s cubic-bezier(.2,.8,.2,1), box-shadow .3s ease, background .3s ease;
}
.sas-popup-form .elementor-button:hover{
  background:linear-gradient(135deg, var(--periwinkle), var(--indigo)) !important;
  transform:translateY(-3px) scale(1.01);
  box-shadow:0 14px 30px -10px rgba(76,111,255,0.6);
}
.sas-popup-form .elementor-field-type-submit{ display:flex !important; justify-content:center; }
.sas-popup-form .elementor-field-type-submit .elementor-button{ width:100%; max-width:100%; }

/* ============================================================
   Floating WhatsApp Button (Elementor Floating Button Fix)
   - Small compact circular pill on both Desktop (46x46) & Mobile (42x42)
   - Solid WhatsApp green gradient (#25D366 -> #128C7E) & white icon
   ============================================================ */
.e-contact-buttons.has-platform-whatsapp,
.elementor-location-floating_buttons {
  position: fixed !important;
  bottom: 22px !important;
  right: 18px !important;
  inset-inline-end: 18px !important;
  inset-inline-start: auto !important;
  margin: 0 !important;
  padding: 0 !important;
  width: auto !important;
  height: auto !important;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  z-index: 99999 !important;
  pointer-events: none !important;
}

.e-contact-buttons.has-platform-whatsapp .e-contact-buttons__chat-button-container {
  padding: 0 !important;
  margin: 0 !important;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  display: inline-flex !important;
  pointer-events: auto !important;
}

.e-contact-buttons.has-platform-whatsapp .e-contact-buttons__chat-button,
.elementor-188 .elementor-element.elementor-element-137f7c1e .e-contact-buttons__chat-button {
  width: 46px !important;
  height: 46px !important;
  min-width: 46px !important;
  min-height: 46px !important;
  max-width: 46px !important;
  max-height: 46px !important;
  padding: 0 !important;
  margin: 0 !important;
  border-radius: 50% !important;
  background-color: #25D366 !important;
  background-image: linear-gradient(135deg, #25D366 0%, #128C7E 100%) !important;
  color: #FFFFFF !important;
  border: none !important;
  box-shadow: 0 8px 20px -4px rgba(37, 211, 102, 0.55), 0 4px 10px rgba(0, 0, 0, 0.35) !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  pointer-events: auto !important;
  cursor: pointer !important;
  touch-action: manipulation !important;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.25s ease !important;
}

.e-contact-buttons.has-platform-whatsapp .e-contact-buttons__chat-button svg,
.e-contact-buttons.has-platform-whatsapp .e-contact-buttons__chat-button svg path {
  width: 23px !important;
  height: 23px !important;
  fill: #FFFFFF !important;
  color: #FFFFFF !important;
  display: block !important;
  pointer-events: none !important;
}

@media (max-width: 767px) {
  .e-contact-buttons.has-platform-whatsapp,
  .e-contact-buttons.has-platform-whatsapp.has-h-alignment-end,
  .e-contact-buttons.has-platform-whatsapp.has-v-alignment-bottom {
    bottom: 18px !important;
    right: 16px !important;
    left: auto !important;
    inset-inline-end: 16px !important;
    inset-inline-start: auto !important;
    width: auto !important;
    max-width: 100vw !important;
    pointer-events: none !important;
  }

  .e-contact-buttons.has-platform-whatsapp .e-contact-buttons__chat-button,
  .elementor-188 .elementor-element.elementor-element-137f7c1e .e-contact-buttons__chat-button {
    width: 42px !important;
    height: 42px !important;
    min-width: 42px !important;
    min-height: 42px !important;
    max-width: 42px !important;
    max-height: 42px !important;
  }

  .e-contact-buttons.has-platform-whatsapp .e-contact-buttons__chat-button svg,
  .e-contact-buttons.has-platform-whatsapp .e-contact-buttons__chat-button svg path {
    width: 20px !important;
    height: 20px !important;
    pointer-events: none !important;
  }
}

/* About eyebrow centered on mobile */
@media (max-width:767px){
  .elementor-element-030c8b0, .elementor-element-030c8b0 .elementor-heading-title{ text-align:center !important; }
}

/* Contact form - balanced sizing v2 */
#contact .sas-form .elementor-field-type-text input,
#contact .sas-form .elementor-field-type-email input,
#contact .sas-form .elementor-field-type-url input,
#contact .sas-form .elementor-field-type-tel input,
#contact .sas-form .elementor-field-type-select select{ padding:11px 14px !important; font-size:14px !important; }
#contact .sas-form .elementor-field-type-textarea textarea{ min-height:92px !important; padding:11px 14px !important; font-size:14px !important; }
#contact .sas-form .elementor-field-type-upload input[type=file]{ padding:9px 14px !important; }
#contact .sas-form .elementor-field-label{ font-size:11.5px !important; }
#contact .sas-form .elementor-button,
#contact .sas-form form button[type=submit],
#contact .elementor-element-8983dd1 .elementor-button{ padding:11px 24px !important; font-size:14px !important; min-height:0 !important; line-height:1.2 !important; }
#contact .sas-form .elementor-field-type-submit .elementor-button,
#contact .sas-form form button[type=submit],
#contact .elementor-element-8983dd1 .elementor-button{ width:78% !important; margin-left:auto !important; margin-right:auto !important; display:flex !important; justify-content:center; }
@media (max-width:767px){ #contact .sas-form .elementor-field-type-submit .elementor-button, #contact .sas-form form button[type=submit], #contact .elementor-element-8983dd1 .elementor-button{ width:100% !important; } }

/* Project details textarea - smaller */
#contact .sas-form .elementor-field-type-textarea textarea{ height:100px !important; min-height:100px !important; max-height:180px; resize:vertical; }

/* Footer contrast fix (WCAG AA) */
.elementor-element-cd095c6, .elementor-element-cd095c6 *, .elementor-element-e4db281, .elementor-element-e4db281 *{ color:#9aa0bd !important; }


/* ============================================================
   Header Navigation Underline Pointer Position Fix
   Keeps the hover line directly beneath the menu text,
   rather than stretching down to the bottom border of the header.
   ============================================================ */
.sas-header .elementor-nav-menu--main {
  min-height: auto !important;
  height: auto !important;
  align-self: center !important;
}
.sas-header .elementor-nav-menu {
  height: auto !important;
  align-items: center !important;
}
.sas-header .elementor-nav-menu > li {
  height: auto !important;
  align-items: center !important;
  padding: 0 14px !important;
}
.sas-header .elementor-nav-menu--main .elementor-item {
  height: auto !important;
  padding: 6px 0 !important;
  position: relative !important;
  display: inline-flex !important;
  align-items: center !important;
}
.sas-header .elementor-nav-menu--main .elementor-item::after,
.sas-header .elementor-nav-menu--main .elementor-item::before {
  bottom: -2px !important;
  left: 0 !important;
  right: 0 !important;
  width: 100% !important;
  height: 2px !important;
  border-radius: 2px;
}

/* Nav Menu Hover Exclusivity: Never show 2 underlines or 2 active states at the same time */
.elementor-nav-menu--main:hover .elementor-item.elementor-item-active:not(:hover)::after,
.sas-nav .elementor-nav-menu--main:hover .elementor-item.elementor-item-active:not(:hover)::after,
.elementor-nav-menu--dropdown:hover .elementor-item.elementor-item-active:not(:hover)::after {
  opacity: 0 !important;
  visibility: hidden !important;
  transition: opacity 0.15s ease, visibility 0.15s ease !important;
}

.elementor-nav-menu--main:hover .elementor-item.elementor-item-active:not(:hover),
.sas-nav .elementor-nav-menu--main:hover .elementor-item.elementor-item-active:not(:hover),
.elementor-nav-menu--dropdown:hover .elementor-item.elementor-item-active:not(:hover) {
  color: rgb(124, 130, 160) !important;
  transition: color 0.15s ease !important;
}

/* Prevent clicked link from keeping a sticky focus underline */
.elementor-nav-menu--main .elementor-item:focus:not(:focus-visible):not(.elementor-item-active)::after {
  opacity: 0 !important;
}
.elementor-nav-menu--main .elementor-item:focus:not(:focus-visible):not(.elementor-item-active) {
  color: rgb(124, 130, 160) !important;
}


/* Mobile Navigation Dropdown Solid Theme Background */
.sas-nav .elementor-nav-menu--dropdown,
.elementor-nav-menu--dropdown,
.elementor-nav-menu__container.elementor-nav-menu--dropdown {
  background: #101426 !important;
  background-color: #101426 !important;
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.65) !important;
  border-top: 1px solid rgba(255, 255, 255, 0.08) !important;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08) !important;
}
.sas-nav .elementor-nav-menu--dropdown a,
.elementor-nav-menu--dropdown a,
.elementor-nav-menu--dropdown .elementor-item {
  color: #C9D4FF !important;
  background: transparent !important;
}
.sas-nav .elementor-nav-menu--dropdown a:hover,
.sas-nav .elementor-nav-menu--dropdown a:focus,
.elementor-nav-menu--dropdown a:hover,
.elementor-nav-menu--dropdown a:focus,
.elementor-nav-menu--dropdown .elementor-item:hover,
.elementor-nav-menu--dropdown .elementor-item:focus {
  color: #FFFFFF !important;
  background: rgba(76, 111, 255, 0.14) !important;
}
#home .hero-graph, svg#heroGraph {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  z-index: 0 !important;
  pointer-events: none !important;
  opacity: 0.5 !important;
}

/* Contact form field contrast */
.elementor-form .elementor-field-textual {
  background-color: #101426 !important;
  color: #EDEEF2 !important;
  border: 1px solid rgba(255, 255, 255, 0.15) !important;
}
.elementor-form .elementor-field-textual:focus {
  border-color: #4C6FFF !important;
}

/* In-page Section Scroll Margin for Sticky Header Clearance */
#about, #services, #portfolio, #resume, #contact, #blog {
  scroll-margin-top: 95px !important;
}
@media (max-width: 767px) {
  #about, #services, #portfolio, #resume, #contact, #blog {
    scroll-margin-top: 85px !important;
  }
}