/* ==========================================================================
   sibyl-custom.css
   Hand-written additions to the Sibyl Systems Webflow export, 11 Nov 2026.
   NOT generated by Webflow. Webflow is abandoned (decision: Benedict,
   11 Nov 2026); this file and the HTML are the source of truth.

   Rules:
   - Every value here is derived from an existing declaration in
     css/sibylsystems.webflow.css. No new fonts, no new colours.
   - Keep this file tiny. Prefer reusing an existing Webflow class over
     adding a rule here.
   ========================================================================== */

/* 1. The Ɛ character (U+0190) in "Ɛfie".
      Verified 11 Nov 2026 with headless Chrome + pdffonts: Source Sans Pro
      has no Ɛ glyph, so Chrome substitutes an arbitrary system font for that
      one letter (it picked Helvetica-Bold) while rendering the rest of the
      word in Source Sans Pro. Montserrat DOES have Ɛ, ɛ, ɔ and ẹ, and this
      site already loads Montserrat 100-900 via WebFont.load. Chaining it
      after Source Sans Pro makes the missing glyph fall back to a font the
      site already uses. Every other character is still found in Source Sans
      Pro first, so nothing else changes.
      Selectors mirror the four Source-Sans-Pro declarations that carry
      visible "Ɛfie" text. */
body,
.hero-main-title,
.subpage-title,
.page-subtitle {
  font-family: "Source Sans Pro", Montserrat, sans-serif;
}

/* 2. Spacing for the App Store / Google Play badge pair in the homepage hero.
      35px matches .hero-main-title.subtitle's own margin-top (line 2515 of
      sibylsystems.webflow.css); 20px matches its 479px margin-top (line 6845).
      The badges themselves need no new CSS: .app-store-link-button (line 2706)
      and .app-store-button (line 2701) already exist and were unused. */
.hero-store-badges {
  margin-top: 35px;
}

@media screen and (max-width: 479px) {
  .hero-store-badges {
    margin-top: 20px;
  }
}

/* 3. Mobile app development page (portfolios/mobile-app-development.html). */

/* 3a. Google Play star rating in the Ɛfie testimonial slider. No font the
       page loads has a star glyph and there is no star image in the repo, so
       the stars are inline SVG reusing the five-pointed polygon from
       images/flag-ghana.svg. Only the colour and spacing live here. */
.testimonial-stars {
  fill: #ebba1f;   /* .social-button.rss background-color, sibylsystems.webflow.css:3567 */
  margin-top: 5px; /* .testimonial-name.subtitle margin-top, sibylsystems.webflow.css:945 */
}

/* 3b. Let the testimonial slider grow to fit the real Google Play reviews.
       Measured 11 Nov 2026 in headless Chrome: the longest review makes
       .testimonial-block 214px tall, but .testimonial-slider is height:200px
       (line 877) and .w-slider-mask is overflow:hidden, so without this rule
       7px is cut off the top and bottom and the last 1px of the stars
       disappears.
       The clipping does not pre-date this change. Re-measured at HEAD
       (e83c3b2) by replaying the committed markup: the taller of the two old
       .testimonial-blocks was 183px inside the same 200px mask, i.e. 8.5px of
       slack at each edge, nothing clipped. The 214px block, and so the need
       for height: auto, arrives with the longer Google Play review copy added
       in this same change.
       This gives 1440/1200/991 the behaviour the 767 breakpoint already has.
       The two rules MUST stay together: with the container still absolutely
       positioned, an auto-height slide collapses to zero.
       Only portfolios/mobile-app-development.html uses these two classes
       (verified by grep across public/*.html, 11 Nov 2026). */
.testimonial-slider {
  height: auto; /* .testimonial-slider at 767, sibylsystems.webflow.css:5127 */
}

.container.testimonial-container {
  position: relative; /* .container.testimonial-container at 767, sibylsystems.webflow.css:4966 */
  top: 0%;            /* same rule, sibylsystems.webflow.css:4967 */
  transform: none;    /* same rule, sibylsystems.webflow.css:4968 */
}

/* 3c. Hero artwork swapped to the Ɛfie app phone (images/efie-hero-phone.webp,
       910 x 1805, ratio 0.504). The export's width: 455px
       (sibylsystems.webflow.css:1100) was drawn for the old 1312 x 1717
       iphone-hand-2.png (ratio 0.764); at the new ratio 455px renders 903px
       tall and spills out of a 632px hero. These widths are the largest that
       keep the whole phone inside .iphone-hero, which is overflow: hidden
       (line 2690):
         >= 992px:   room = 632 - 80 = 552px; 552 x 910/1805 = 278.3 -> 278px
                     632 = padding-top 200 (line 2688) + 302px text block
                           (measured) + padding-bottom 130 (line 2689)
                      80 = padding-top 200 (line 2688) + top: -120px (line 1102)
         768-991px:  room = 556 - 190 = 366px; 366 x 910/1805 = 184.5 -> 184px
                     556 = padding-top 160 (line 4659) + 316px text block
                           (measured) + padding-bottom 80 (line 4660)
                     190 = padding-top 160 (line 4659) + top: 30px (line 4302)
                     (185px measures 366.9px tall and clips by 0.9px, so the
                      ratio is rounded down here, not to nearest)
       184px also removes a pre-existing 37px overlap between the old artwork
       and the hero text at 991px.
       Nothing is needed below 768px: w-hidden-small (webflow.css:656) and
       w-hidden-tiny (webflow.css:719) give display: none !important at 767 and
       479, so the .hero-mockup-image overrides at lines 5235 and 6461 are dead
       code on this page.
       The file is still downloaded there, though. display: none does not
       suppress an img element's src fetch, and loading="lazy" was the only
       thing that had been suppressing it; this change removed that attribute.
       Measured in Chrome 11 Nov 2026: at 479 and at 767 the img reports
       complete: true with naturalWidth/naturalHeight 910/1805, and the HTTP
       access log shows GET /images/efie-hero-phone.webp 200 (42 requests at
       479 against 41 at desktop). So visitors at 767px and below now pull
       117KB (119,474 bytes) of webp for an element they never see. That is a
       pending decision for Benedict, not an oversight.
       Scoped with a .mobile-hero modifier, exactly like the export's own
       .hero-mockup-image.desktop-hero (line 1106), because
       portfolios/desktop-app-development.html and
       portfolios/website-development.html also use .hero-mockup-image and
       still carry the old 0.76-ratio artwork. Both queries are min-width so
       they can never override the 767px and 479px rules. */
@media screen and (min-width: 768px) {
  .hero-mockup-image.mobile-hero {
    width: 184px;
  }
}

@media screen and (min-width: 992px) {
  .hero-mockup-image.mobile-hero {
    width: 278px;
  }
}

/* 3d. The three-phone montage beside "Transforming Mobile Experiences".
       The export sets .devices-mockup-right height: 565px with no width
       (lines 1143-1148), which breaks two ways. Once loaded, the image takes
       its natural 878.7px width and right: -450px (line 1147) throws its right
       edge to x=1640 at a 1440 viewport, 200px past the window: 23-48% of the
       montage is clipped on desktop, always including the entire right-hand
       phone, and at 992px and up the img box overlaps .info-block-left by 15px
       (measured with these rules disabled: 77.2% of the montage visible at
       1440, 63.6% at 1200, 62.0% at 991, clearance -15.06px at 1440 and 1200).
       Before the bitmap arrives the img computes to width: 0 at x=1640,
       outside the section's overflow: hidden, and with alt="" there is no
       placeholder either, so it renders as literally nothing - which is the
       reported symptom.
       What a width plus height: auto actually buys, all measured 11 Nov 2026,
       is three things, and only the first is viewport-independent:
         1. The overlap is fixed outright. Clearance to .info-block-left is
            23.61px at every width from 992 up, and 30.33px from 991 down to
            798, narrowing to 17.13px at 768 where .container's 35px side
            margins bind instead of its 728px cap. Positive throughout.
         2. The montage is fully visible at 1440 and wider. Below that it bleeds
            progressively: 94.2% visible at 1366, 87.5% at 1280, 81.3% at 1200,
            73.4% at 1100, 65.0% at 992 (the worst case, 224px cut), then
            78.1% at 991 and 60.2% at 768. So at 992-1100 the right-hand phone
            is mostly cut. That is inherent, not a residual bug: right is a
            fixed negative px measured against a container capped at 940px by
            .w-container (webflow.css:509) and at 728px below 992 (:598), so
            the bleed can only track the viewport. It is also what the model
            class does - .browser-mockup-right bleeds off the right edge on
            purpose - so the behaviour is the borrowed one, not a side effect.
         3. The explicit width removes the pre-load and failure state described
            above: a 0px-wide box at x=1640, entirely outside the section's
            overflow: hidden clip, which with alt="" renders as nothing at all.
       Every value comes from .browser-mockup-right, this site's own right-hand
       mockup that deliberately bleeds off the right edge:
         >= 992px:   width 640px (line 1984), top 20px (line 1987),
                     right -250px borrowed from line 4473, which is
                     .browser-mockup-right's 768-991px declaration - NOT from
                     line 1988, its own >= 992px one, which is -240px.
                     Which of the two is used only matters at exactly 1440:
                     the empty strip of container left to the right of the
                     montage is W/2 - 710 for -240px and W/2 - 720 for -250px,
                     so at 1440 -250px lands flush with the window edge while
                     -240px leaves a 10px strip. Above 1440 neither value
                     bleeds at all and the strip just grows with the viewport
                     (-240px: 90px at 1600, 250px at 1920; -250px: 240px at
                     1920). Guaranteeing a bleed at 1440 and wider would take
                     about -300px, which has no precedent anywhere in the
                     export, so it was not invented.
         768-991px:  width 540px (line 4471), top 90px (line 4472),
                     right -250px (line 4473)
       height: auto is .devices-mockup-right's own 767px value (line 5253) and
       is mandatory: without it height: 565px (line 1144) survives and
       stretches the montage to 640 x 565.
       Nothing is needed below 768px: line 5251 already gives width: 100%,
       height: auto, position: relative, top: 0, right: 0, and it measures
       correctly (697 x 448 at 767, 439 x 282 at 479, fully visible).
       Scoped with a .mobile-app modifier because index.html uses
       .devices-mockup-right as well, with different artwork. min-width only,
       for the same reason as 3c. */
@media screen and (min-width: 768px) {
  .devices-mockup-right.mobile-app {
    width: 540px;
    height: auto;
    top: 90px;
    right: -250px;
  }
}

/* Only the two values that change are restated here. height: auto and
   right: -250px are not forgotten: the min-width: 768px block above also
   matches at >= 992px and sets them to the same values, so they carry over. */
@media screen and (min-width: 992px) {
  .devices-mockup-right.mobile-app {
    width: 640px;
    top: 20px;
  }
}


/* 4. "Meet the Team" cards (about/about.html). Two-column card: 170x140 photo
      beside a name/role/bio column. The export floats .team-image left
      (sibylsystems.webflow.css:7253) and leaves the three text blocks as
      full-width siblings, so their line boxes shorten beside the float and
      then snap back to the wrapper's left edge below it, running the bio under
      the photo. Worst at 768-991px, where the card is still 50% of a 728px
      container and the text channel is only 144px wide. A flex row gives the
      text its own column instead, and the HTML now wraps the three text blocks
      in .team-text so they are one flex item rather than three.
      .team-wrapper is used only by about.html (checked every file in public/),
      so the bare selector is safe. The w-clearfix class was removed from both
      wrappers in the HTML: there is no float left to clear, and
      .w-clearfix:before/:after (webflow.css:72-83) would become two stray flex
      items a few px wide, one at each end of the row.
      flex-shrink: 0 is load-bearing, not tidying: .team-text's max-content
      basis is wider than the card, so with a short bio the photo would be
      squeezed below the export's own width: 170px (line 7251), which is the
      declaration it holds in place. It is the one property here that the export
      never uses itself.
      display: grid, gap, flex: 1 and min-width: 0 were considered and left out
      because reusing declarations the export already makes covered the need
      with less CSS: the 40px photo gap is the export's own .team-image
      margin-right, and .team-text needs no rule because as the only other flex
      item it already takes the remaining width.
      Leaving out min-width: 0 has one consequence worth knowing: a flex item's
      automatic minimum size is its min-content width, so .team-text cannot
      shrink below its longest unbreakable token, and a future bio carrying a
      long email address or URL would widen the card past its column (measured
      11 Nov 2026 at 480px, where the channel is tightest at 200px: a
      39-character email address overflowed by 44px). Today's longest token is
      the hyphen-breakable "language-expansion", so there is no present defect.
      Comment only - no declaration was added for it. */
.team-wrapper {
  display: flex; /* .center-things display, sibylsystems.webflow.css:7206 */
}

.team-image {
  flex-shrink: 0; /* hold the export's width: 170px, sibylsystems.webflow.css:7251 */
}

/* 4a. At 991px and below the card is too narrow for two columns, so stack the
       photo above the text and give the bio the card's full width. */
@media screen and (max-width: 991px) {
  .team-wrapper {
    flex-direction: column; /* flex-direction, sibylsystems.webflow.css:627;
                               column value cf. .feature-info-row
                               flex-flow: column, line 2458 */
  }

  .team-image {
    margin-right: 0;
    margin-bottom: 20px; /* .team-wrapper margin-bottom, sibylsystems.webflow.css:7246 */
  }
}

/* 4b. At 767px and below .w-col goes full width (webflow.css:664), so the card
       is wide again (~487px of text channel at 767px) and the photo fits beside
       the text. Safe to go back to a row: .team-text is its own flex item, so
       the bio cannot wrap under the photo however long it gets. */
@media screen and (max-width: 767px) {
  .team-wrapper {
    flex-direction: row; /* flex-direction: row, sibylsystems.webflow.css:627 */
  }

  .team-image {
    margin-right: 40px; /* restores .team-image margin-right, sibylsystems.webflow.css:7258 */
    margin-bottom: 0;
  }
}

/* 4c. Below 479px the viewport itself keeps narrowing on real phone widths: the
       409px card gives a ~200px channel at the break, but the photo's fixed
       170px and its 40px gap would leave only ~40px at 320px, so stack again. */
@media screen and (max-width: 479px) {
  .team-wrapper {
    flex-direction: column; /* as 4a above */
  }

  .team-image {
    margin-right: 0;
    margin-bottom: 20px; /* .team-wrapper margin-bottom, sibylsystems.webflow.css:7246 */
  }
}
