/* ==========================================================================
   Mobile layout — Figma frame 3116:689, 393 x 5729
   --------------------------------------------------------------------------
   The desktop page is pinned to a 1920 artboard through the --u unit. This
   file is the same idea against the second frame: below 900px, js/main.js
   redefines --u as viewport/393, and every length here is the number straight
   off the mobile frame. Two coordinate spaces, one mechanism, no arithmetic
   in the middle.

   Nothing here overrides the desktop file's values in general — it only
   restates the ones the mobile frame changes. Anything the two layouts agree
   on (colours, fonts, the tokens) is inherited untouched.
   ========================================================================== */

@media (max-width: 899px) {

  /* ---- The artboard --------------------------------------------------- */
  /* Past 452px the artboard stops growing (see the cap in main.js) and is
     centred instead. The white sections then have to reach past it, or the
     page background would show as dark bands down both sides. */
  .page {
    position: relative;
    width: calc(393 * var(--u));
    margin-inline: auto;
  }

  /* Figma path M393 833V0L250.5 118.5H158.5L0 71.5V833H393Z — the top edge
     drops from the right corner to 118.5, runs flat, and climbs back to 71.5
     on the left. It is carved to sit under the wave, which is why a straight
     edge read as wrong however the wave was layered against it.

     Full-bleed by its own width rather than by a spread shadow, because a
     shadow cannot be clipped into a shape. */
  .section--white {
    width: 100vw;
    margin-inline: calc(50% - 50vw);
    clip-path: polygon(
      100% 0,
      63.74% calc(118.5 * var(--u)),
      40.33% calc(118.5 * var(--u)),
      0 calc(71.5 * var(--u)),
      0 100%,
      100% 100%);
  }

  /* ---- Hero ------------------------------------------------------------ */
  /* 696 is where the white section's shape begins on the mobile frame. */
  /* The button column ends at 704 while the hero ends at 696, so the ghost
     button was being cut off by the hero's own overflow. It is meant to sit
     in that gap: the white band below dips to 118.5 in the middle, so there
     is room there for it. */
  .hero { height: calc(696 * var(--u)); overflow: visible; }

  /* The mobile frame reuses the footer background for the hero, flipped.
     Drawn here rather than swapped in the markup so the desktop's own two
     background images are left exactly as they are. */
  .page-bg { display: none; }

  .hero::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: calc(393 * var(--u));
    height: calc(607 * var(--u));
    /* The frame holds the full width and the picture is scaled to 220.65% and
       pushed left inside it, rather than the box itself being oversized. */
    background: url("../assets/img/footer-flat-ink.webp") no-repeat;
    background-size: calc(867.15 * var(--u)) calc(607 * var(--u));
    background-position: calc(-474.08 * var(--u)) 0;
    transform: scaleY(-1);
    pointer-events: none;
  }

  /* The wave. Figma centres the rotated image inside a bounding frame, so as
     everywhere else it is placed by that frame's centre — (-131.0, 929.39) —
     which is the one point rotation cannot move. */
  /* ---- No filter on the waves here ------------------------------------
     THE PURPLE SCREEN. filter: saturate() forces an element onto a texture of
     its own at device resolution, and these two are drawn 1472x1032 CSS on a
     393 frame — 4698x3512 and 5249x4512 device pixels on a 3x phone, 63MB and
     90MB. Both axes are past the 4096 texture limit most mobile GPUs enforce,
     and a layer that cannot be rasterised gets painted as a flat fill. That is
     the purple panel, and it appeared in About because the 90MB one is the
     About wave.

     Dropping the filter lets the browser draw them as ordinary images from the
     1672x941 bitmap it already decoded, with no intermediate at all. The cost
     is that mobile loses the 0.85 desaturation — the waves read very slightly
     more colourful here than on the desktop. Bake it into the asset if that
     ever matters; do not put the filter back. */
  .wave { filter: none; }

  .wave--hero {
    left: calc(-131 * var(--u));
    top: calc(929.39 * var(--u));
    width: calc(1472.263 * var(--u));
    height: calc(1031.96 * var(--u));
    transform: translate(-50%, -50%) rotate(-5.6deg);
  }

  .wave--about { display: none; }   /* placed with the About section, later */

  /* ---- The wordmark ---------------------------------------------------- */
  /* Two lines on mobile, and plain text rather than the WarpText canvas: that
     effect answers a pointer, and a touch screen has none to answer. */
  .display--hero {
    top: calc(105 * var(--u));
    font-size: calc(174.234 * var(--u));
    letter-spacing: calc(-8.7117 * var(--u));
    line-height: 0.83;
    white-space: normal;
    width: calc(393 * var(--u));
    left: 50%;
  }

  /* .hero__copy is the positioned block; the tagline and the buttons flow
     inside it, exactly as they do on the desktop. */
  /* The 393 frame has caught up: it now carries the line she added, at 508,
     with the body at 544 and the buttons at 640. Read straight off it. */
  .hero__copy {
    left: 50%;
    top: calc(508 * var(--u));
    width: calc(306 * var(--u));
    translate: -50%;
    text-align: center;
  }

  /* Figma 3169:326 — 20 and bold here, against 24 on the 1920 frame, and now
     broken over two lines after "היי, אני צביה". The break is inserted from
     main.js behind this same media query: a <br> in the markup would reach the
     desktop, where the line runs at 24 across a 487 box and does not break. */
  .hero__lead {
    font-size: calc(20 * var(--u));
    line-height: 1.2;
    margin-bottom: calc(15.2 * var(--u));
  }

  .hero__tagline { font-size: calc(16 * var(--u)); line-height: 1.3; }

  /* Figma 3130:414 — the label and the mark sit side by side on one baseline,
     centred together, rather than the mark hanging below the words. */
  /* Figma 3130:414 puts the label and the mark on one baseline: a 180-wide
     label and a 20-wide mark, 12 apart, the pair centred on 198. Placed by
     coordinate rather than by nesting, because the mark has to stay a sibling
     for the desktop to keep its own position. */
  .hero__badge { left: calc(107 * var(--u)); top: calc(412 * var(--u)); translate: none; }

  .hero__made { font-size: calc(18 * var(--u)); width: calc(180 * var(--u)); }

  /* Node 3123:857, 38 square. The frame's x is 287, but Cooperative sets
     DESIGN wider here than it does in Figma: measured, the N runs 294.2 to 362,
     so the frame's 287 does not land where it lands in Figma.
     Measured off the glyph itself rather than off its box: drawn at 300px,
     Cooperative's N inks from 37 to 135 with a left side bearing of 17, and
     its two legs are [37,68] and [104,135] — so the LEFT leg centres 15.5 in
     from the ink edge. Scaled to 174.234 and added to the letter's pen
     position (292.3), that is x 311.2. The drop is a circle of radius 19
     centred in its own 38 box, so its left goes to 292.2.
     Re-measure if the wordmark's size ever changes. */
  .hero__mark {
    left: calc(292.2 * var(--u));
    top: calc(388 * var(--u));
    width: calc(38 * var(--u));
    height: calc(38 * var(--u));
    translate: none;
  }

  /* ---- Hero buttons ---------------------------------------------------- */
  /* Stacked and full width of their column, and the order is reversed from
     the desktop: on the mobile frame the solid CTA sits on top. */
  /* Side by side now, not stacked — Figma 3123:855: one 321 row at 640, gap 8,
     the two children sharing the width equally.

     row-REVERSE, and the reason is the markup order. The desktop frame reads
     ghost then solid left to right and the markup follows it; the 393 frame
     puts the solid one on the left. Reversing the row is what puts them in her
     order without touching the HTML the desktop depends on. */
  .hero__actions {
    flex-direction: row-reverse;
    gap: calc(8 * var(--u));
    width: calc(321 * var(--u));
    margin: calc(33.6 * var(--u)) auto 0;
  }

  /* flex:1 so the pair splits the 321 evenly. The 36 of side padding the frame
     gives a full-width button does not survive being halved — at 156.5 each
     there is not room for it and the label — so it comes down to 10 and the
     label is what decides the shape. */
  .hero__actions .btn,
  .hero__actions .btn--ghost,
  .hero__actions .btn--solid {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    font-size: calc(16 * var(--u));
    padding-inline: calc(10 * var(--u));
  }

  /* ---- Grid lines and rain --------------------------------------------- */
  /* The hero band is respaced for the narrow frame; the other two are pinned
     to desktop page coordinates that mean nothing here and are placed with
     their sections when those are built. */
  /* Four, not ten, and sitting on the background rather than spanning the
     page: left 77, width 237.32, starting 101.42 above the hero. */
  /* 238.32, not the frame's 237.32. The band clips to its own box and the
     fourth line sits at left 237.16, so 0.16 of its width fell outside it and
     what was left was a sub-pixel sliver at 20% opacity — nothing you could
     see. Every line keeps its Figma x; the invisible band is just given the
     one unit it needs to show the last of them. */
  .grid-lines__band { left: calc(77 * var(--u)); width: calc(238.32 * var(--u)); }

  .grid-lines__band--hero {
    top: calc(-101.42 * var(--u));
    height: calc(915.596 * var(--u));
  }

  .grid-lines__band--about,
  .grid-lines__band--quotes { display: none; }

  /* The ten hairlines carry desktop offsets measured against a 1570-wide band.
     Inside a 353-wide one they ran a thousand pixels off the page, taking the
     raindrops that hang on them along. Respaced across the narrow band. */
  /* Figma draws these at 20% purple. At 393 wide that is almost nothing on a
     phone screen, so they are lifted to 34% — above the frame value on
     purpose, because the frame value was invisible in practice. */
  /* The frame's own values: #9F93FF at 20%, 0.31963 wide. */
  /* The frame's 0.32 is a sub-pixel width: the browser draws it by fading the
     line rather than by drawing it, so 20% of a third of a pixel is barely
     ink. A full unit is a real hairline, and the alpha then does the softening
     — 0.07, not 0.2: at full width the line was reading as a drawn rule rather
     than as structure you half-notice. The width stays a whole unit so it is
     still a real line the browser draws; only the ink comes down. */
  .grid-lines__band span {
    background: rgba(159, 147, 255, 0.07);
    transform: none;
    width: calc(1 * var(--u));
  }

  .grid-lines__band span:nth-child(1) { left: calc(0.16 * var(--u)); }
  .grid-lines__band span:nth-child(2) { left: calc(78.77 * var(--u)); }
  .grid-lines__band span:nth-child(3) { left: calc(158.16 * var(--u)); }
  .grid-lines__band span:nth-child(4) { left: calc(237.16 * var(--u)); }

  /* The markup carries ten for the desktop bands. The mobile frame draws four,
     and marquee.js hangs one raindrop on each line it finds visible — so
     hiding the rest also gives four drops rather than ten. */
  .grid-lines__band span:nth-child(n+5) { display: none; }

  /* Both desktop glows are 2300+ wide and drawn for a 1920 artboard. The
     mobile frame has its own pair; until those are placed these would only
     smear the page and drag its width out. */
  .glow-blob { display: none; }

  /* ---- Pointer-only devices -------------------------------------------- */
  /* All three answer a mouse. None of them has anything to answer here, and
     each costs either battery or a wrong-looking idle state. */
  .dot-field,
  .tile-warp,
  .explore-cursor { display: none; }

  .tile.is-warped-tile img { visibility: visible; }

  /* ---- Sections become flow ------------------------------------------- */
  /* The desktop sections are fixed-height canvases with everything placed on
     them by coordinate. On a phone that inverts: the content sets the height
     and the blocks simply stack. Every rule below is a consequence of that
     one decision. */
  .why, .projects, .about, .everything, .testimonials, .contact { height: auto; }
  .projects.is-exhausted { height: auto; }

  .section-edge { display: none; }

  /* ---- Why Me + Everything You Need (identical, per the brief) ---------- */
  /* 260 rather than 120: the wave crosses the top of this band, and at 120 the
     first card was sliding under it. */
  .why { padding: calc(278.5 * var(--u)) 0 calc(72 * var(--u)); }
  .everything { padding: calc(140 * var(--u)) 0 calc(72 * var(--u)); }

  .why__inner, .everything__inner {
    position: static;
    display: flex;
    flex-direction: column;
    gap: calc(20 * var(--u));
    width: calc(325 * var(--u));
    margin-inline: auto;
    transform: none;
    translate: none;
  }

  /* A real column, not display:contents. A sticky child of a box that does not
     exist has no containing block to be constrained by, and the pin was
     releasing about a third of the way through the section. */
  .why__row, .everything__col {
    display: flex;
    flex-direction: column;
    width: 100%;
    gap: 0;
  }

  /* Matched to the specificity of the desktop rules that size the bento
     cards (.why__row .card and friends) — a bare .card selector loses to them
     and the cards stayed at their desktop widths. */
  .why__row .card,
  .why__row .card--tall,
  .why__inner > .card--wide,
  .everything__col .card,
  .card--side,
  .card {
    position: static;
    width: 100%;
    height: auto;
    padding: calc(36 * var(--u)) calc(48 * var(--u));
  }

  .card__num   { font-size: calc(64 * var(--u)); }
  .card__title { font-size: calc(24 * var(--u)); width: auto; }
  .card__text  { font-size: calc(16 * var(--u)); }

  /* The rotated wordmark from the frame, behind the cards.

     Two different constructions: Why Me rotates an inner span and drifts on
     its own animation, so the wrapper is only repositioned here. Everything
     You Need is a bare line of text, so it is rotated itself — and that needs
     to outrank [data-anim].is-in, which resets transform to none when the
     element reveals. */
  .why .display--why {
    left: calc(-60 * var(--u));
    top: calc(120 * var(--u));
    width: calc(140 * var(--u));
    height: calc(560 * var(--u));
    translate: none;
    animation: none;
  }

  /* Sized to the deck, not to the frame. The finished stack runs 201 to 717.7
     — 516.7 tall — and the wordmark is meant to measure exactly that, so the
     frame's 202.362 is scaled by 516.7/580.4. Re-derive both numbers if the
     deck's 112 step or the card heights change. */
  .why .display--why > span {
    font-size: calc(180.16 * var(--u));
    letter-spacing: calc(-3.603 * var(--u));
  }

  .everything .display--everything {
    left: calc(-30 * var(--u));
    top: calc(120 * var(--u));
    translate: none;
    transform: rotate(90deg);
    transform-origin: left top;
    font-size: calc(96 * var(--u));
    letter-spacing: calc(-1.9 * var(--u));
    white-space: nowrap;
  }

  /* ---- Projects -------------------------------------------------------- */
  .projects { padding: calc(170 * var(--u)) 0 calc(40 * var(--u)); z-index: 2; }

  .display--projects {
    top: calc(20 * var(--u));
    font-size: calc(165.931 * var(--u));
    letter-spacing: calc(-3.3186 * var(--u));
  }

  .projects__sets { position: static; }

  .projects__set, .projects__set--split { height: auto; }
  .projects__set + .projects__set { margin-top: calc(28 * var(--u)); }

  .projects__grid {
    position: static;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: calc(28 * var(--u));
    width: 100%;
  }

  .projects__col, .projects__pair { display: contents; }

  /* One column of identical tiles. The bento's shapes are a desktop idea —
     at 321 wide there is no mosaic to make. */
  .projects .tile,
  .tile--a, .tile--b, .tile--c, .tile--d, .tile--e, .tile--f, .tile--g,
  .projects__set--split .tile--f {
    position: relative;
    left: auto;
    top: auto;
    width: calc(321 * var(--u));
    height: calc(347.027 * var(--u));
    border-radius: calc(8.676 * var(--u));
    margin-inline: auto;
  }

  /* The caption js/projects.js adds below each tile on touch, carrying the
     name and the link that the hover badge carries on the desktop. */
  .tile-caption {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    width: calc(321 * var(--u));
    margin: calc(12 * var(--u)) auto 0;
    font-family: var(--f-body);
    font-size: calc(16 * var(--u));
    line-height: 1.2;
  }

  .tile-caption__name { color: var(--c-white); opacity: var(--o-body-on-dark); }

  /* direction:rtl, and it matters. .projects forces ltr so the bento keeps
     Figma's column order, and the caption inherits it — which put the trailing
     arrow on the RIGHT of the Hebrew instead of the left. Set here on the link
     alone so the flex order of name and link is untouched.
     cursor:pointer because the whole caption opens the project now (projects.js). */
  .tile-caption__link {
    direction: rtl;
    color: var(--c-purple-light);
    text-decoration: underline;
    text-underline-offset: 0.25em;
  }

  .tile-caption { cursor: pointer; }

  /* A tile the load-more button has not reached yet. */
  .tile.is-held, .tile.is-held + .tile-caption { display: none; }

  .projects__cta {
    position: static;
    margin: 0 auto;   /* .about__inner already spaces it by 30 */
    translate: none;
    text-align: center;
  }

  .projects__cta .btn { font-size: calc(16 * var(--u)); }

  /* ---- About ----------------------------------------------------------- */
  .about { padding: calc(150 * var(--u)) 0 calc(60 * var(--u)); }

  .about__photo img {
    width: 100%;
    height: 100%;
    margin: 0;
    object-fit: cover;
    object-position: 50% 22%;   /* faces sit high in the frame */
  }

  .about__inner {
    position: static;
    width: calc(325 * var(--u));
    margin-inline: auto;
    translate: none;
    transform: none;
    gap: calc(28 * var(--u));
  }

  /* Photo above the name rather than beside it: side by side, the name has to
     shrink past the point where it reads as a heading. */
  .about__head {
    flex-direction: column-reverse;
    align-items: center;
    gap: calc(28 * var(--u));
    margin-bottom: calc(12 * var(--u));
  }

  .about__name { font-size: calc(48 * var(--u)); text-align: center; }
  .about__bio  { width: 100%; font-size: calc(16 * var(--u)); }
  .about__bio p, .about__bio-strong { font-size: calc(16 * var(--u)); }

  .display--about {
    top: calc(10 * var(--u));
    font-size: calc(120 * var(--u));
    letter-spacing: calc(-2.4 * var(--u));
  }

  .about .btn--xl { font-size: calc(16 * var(--u)); }

  /* ---- Contact + footer ------------------------------------------------ */
  .contact { padding: calc(140 * var(--u)) 0 calc(60 * var(--u)); }

  .display--talk {
    top: calc(20 * var(--u));
    font-size: calc(140 * var(--u));
    letter-spacing: calc(-2.8 * var(--u));
  }

  .contact__outro { font-size: calc(16 * var(--u)); width: calc(325 * var(--u)); }
  .contact__cta   { font-size: calc(16 * var(--u)); }

  .site-footer {
    position: static;
    height: auto;
    padding: calc(24 * var(--u)) calc(20 * var(--u)) calc(96 * var(--u));
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: calc(14 * var(--u));
    text-align: center;
  }

  /* Every positioned descendant, not just the three wrappers. The individual
     legal links are pinned by their right edge against the 1920 artboard — at 393 that
     put one of them at left: -107, which in a right-to-left page is real,
     reachable scroll space. The browser then rested inside it and shoved the
     whole page off the right edge. */
  .site-footer__social,
  .site-footer__links,
  .site-footer__copy,
  .site-footer__link,
  .site-footer__link--a11y,
  .site-footer__link--terms,
  .site-footer__link--privacy {
    position: static;
    left: auto;
    right: auto;
    top: auto;
    translate: none;
  }


  /* ---- Corrections, round one ------------------------------------------ */

  /* The bento orders the cards for a mosaic, so stacked they read 2-1-3 and
     2-3-1. Numbered cards have to count. */
  .why__row .card:nth-child(1) { order: 2; }   /* 02 */
  .why__row .card:nth-child(2) { order: 1; }   /* 01 */
  .why__inner > .why__row      { order: 1; }
  .why__inner > .card--wide    { order: 2; }   /* 03, after the pair */

  .everything__col .card:nth-child(1) { order: 1; }   /* 02 */
  .everything__col .card:nth-child(2) { order: 2; }   /* 03 */
  /* 01 lives outside the column and after it in the markup, so both sides of
     the pair need an explicit order to put it first. */
  .everything__inner > .card--side    { order: 1; }
  .everything__inner > .everything__col { order: 2; }

  .why__inner, .everything__inner { flex-wrap: nowrap; gap: calc(20 * var(--u)); }
  .why__row, .everything__col { gap: calc(20 * var(--u)); }

  /* ---- Cards arriving one under the other ------------------------------ */
  /* Not a pile. 01 is simply there; 02 climbs from below and comes to rest
     under it; 03 does the same under 02. The finished state is the plain
     stacked column of the frame, so nothing here survives the animation —
     it only governs how each card gets to its place.

     The site-wide [data-anim] reveal already does exactly this, so the cards
     ride it and only the distance and the pacing are set here. */
  .why__row .card,
  .why__inner > .card--wide,
  .everything__col .card,
  .everything .card--side { position: static; }

  .why .card[data-anim],
  .everything .card[data-anim] {
    transform: translateY(calc(90 * var(--u)));
    transition: opacity 0.9s var(--ease-rise),
                transform 1.1s var(--ease-rise);
  }

  /* The first card is already in place when the section arrives — it has
     nothing to climb over. */
  .why__row .card:nth-child(2)[data-anim],
  .everything__inner > .card--side[data-anim] {
    transform: none;
    transition-duration: 0.5s;
  }

  /* ---- Why Me: a stacking deck ------------------------------------------
     main.js has flattened .why__inner into three sibling cards and marked it
     [data-stack]. All three then sit in ONE grid cell, each dealt 44 lower
     than the one before, and 02 and 03 are lifted into that cell from below
     as the section is scrolled through.

     position:sticky built the same picture and was wrong, for a reason worth
     writing down: sticky pins an element to the VIEWPORT. The section and the
     WHY ME wordmark keep travelling up underneath it, so a pinned 01 slides
     visibly DOWN the section while everything around it rises. Nothing about
     sticky can undo that — it is what sticky is. Holding 01 still inside the
     section means 01 does not move at all, and 02 and 03 move faster than the
     page, which only a scroll-driven transform can do. */
  .why__inner[data-stack],
  .everything__inner[data-stack] {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0;
  }

  /* One cell, three cards, painted in the order they are dealt. align-self
     keeps each at its own natural height instead of stretching to the cell. */
  .why__inner[data-stack] > .card,
  .everything__inner[data-stack] > .card {
    grid-area: 1 / 1;
    align-self: start;
    position: static;
    width: 100%;
    height: auto;
    margin: 0;
  }

  /* 112 is measured, not chosen. Inside a card the number's box runs 37 to
     99.7 from the top edge and the title starts at 123.7 — so a card landing
     112 below the one before clears the whole number with 12 of air under it,
     and still stops 11 short of the title. At the 44 this started on, the card
     on top cut the number below it at the ankles.

     The three numbers reading 01 02 03 down the left of the finished deck is
     the point of the effect, so this is the number to protect: change the
     card's padding or the number's size and this has to be re-measured. */
  .why__inner[data-stack] > .card:nth-child(1),
  .everything__inner[data-stack] > .card:nth-child(1) { z-index: 1; }
  .why__inner[data-stack] > .card:nth-child(2),
  .everything__inner[data-stack] > .card:nth-child(2) { z-index: 2; margin-top: calc(112 * var(--u)); }
  .why__inner[data-stack] > .card:nth-child(3),
  .everything__inner[data-stack] > .card:nth-child(3) { z-index: 3; margin-top: calc(224 * var(--u)); }

  /* ---- The stage ---------------------------------------------------------
     main.js wraps the wordmark and the deck in .why__stage and drops an empty
     .why__run underneath. The stage parks 24 from the top of the screen and
     stays there for the whole height of the run, which is the scroll the three
     cards are dealt over. Nothing inside it moves relative to anything else
     inside it — WHY ME and 01 are locked together, which is the point.

     There is no travel row inside the deck any more. The cards start below
     their places and simply overflow the stage; while the stage is parked the
     section extends far below the screen, so there is nothing to be cut by. */
  .stack-stage {
    position: sticky;
    top: calc(24 * var(--u));
    z-index: 1;
  }

  /* The pace, and the only number that sets it. A sticky element is held
     inside its parent's CONTENT box, so this has to be a real box — padding on
     .why would lengthen the section without lengthening the pin. Taller means
     longer to read; it does not move anything. */
  .stack-run { height: calc(1400 * var(--u)); }

  /* The site-wide fade-up lifts each card 90 on the way in, which is a second
     motion competing with this one. The fade is kept, the travel is not.
     transform, not translate: the climb below uses the translate property so
     the two never overwrite each other. */
  .why__inner[data-stack] > .card[data-anim],
  .everything__inner[data-stack] > .card[data-anim] {
    transform: none;
    transition: opacity 0.7s var(--ease-rise);
  }

  /* A card sliding over another needs an edge you can see. The base .card
     draws a 1px shadow for a white section; against another white card that is
     not enough to separate them.

     box-shadow, and the base .card's drop-shadow filter turned off with it.
     drop-shadow exists so a shadow can follow a transparent PNG's silhouette;
     a card is an opaque rounded rectangle, so the two are indistinguishable
     here — but the filter puts every one of these six cards on a texture of
     its own, and they are the things being animated. Same picture, no layer. */
  .why__inner[data-stack] > .card,
  .everything__inner[data-stack] > .card {
    filter: none;
    box-shadow: 0 calc(-1 * var(--u)) calc(3 * var(--u)) rgba(31, 27, 61, 0.10),
                0 calc(6 * var(--u)) calc(18 * var(--u)) rgba(31, 27, 61, 0.10);
  }

  /* The climb itself is driven from main.js — see there for why it is script
     and not animation-timeline: view(). The cards start translated down into
     the room below and are pulled up to 0 as the section is scrolled through.
     01 is never touched: it does not move. */
  @media (prefers-reduced-motion: reduce) {
    .why__inner[data-stack] > .card,
    .everything__inner[data-stack] > .card { translate: none !important; }
  }

  /* The wordmark rides over the pile rather than under it. */
  .why .display--why,
  .everything .display--everything { z-index: 4; }

  /* Name on the right, link on the left — the page reads right-to-left, and
     the name is what you are looking for. */
  .tile-caption { flex-direction: row-reverse; }

  /* The About CTA is a pill everywhere else on the site. */
  .about .btn--xl,
  .contact .btn--xl,
  .contact__cta { border-radius: var(--r-pill); }

  /* ---- Purple wash ------------------------------------------------------ */
  /* Drawn rather than exported: a radial gradient costs nothing, scales to any
     width and needs no asset. One low behind the cards, one behind the
     projects, both far too soft to read as a shape. */
  .why::after,
  .projects::after,
  .everything::after,
  .testimonials::after {
    content: "";
    position: absolute;
    left: 50%;
    translate: -50%;
    width: calc(700 * var(--u));
    height: calc(700 * var(--u));
    border-radius: 50%;
    pointer-events: none;
    z-index: 0;
    background: radial-gradient(closest-side,
                rgba(159, 147, 255, 0.22), rgba(159, 147, 255, 0) 70%);
  }

  .why::after         { top: calc(-120 * var(--u)); }
  .everything::after  { top: calc(-140 * var(--u)); }
  .projects::after    { top: calc(180 * var(--u)); }
  .testimonials::after{ top: calc(60 * var(--u)); }

  /* The wash sits under everything the section holds. */
  /* Lifted above the wash. top:auto matters — position:relative here revives
     the desktop offsets these carry (.projects__sets is pinned 392 down the
     1920 artboard), which reappeared as a 380px hole above the first tile. */
  .why__inner, .everything__inner, .projects__sets,
  .projects__cta, .quotes, .testimonials__kicker {
    position: relative;
    z-index: 1;
    top: auto;
    left: auto;
    right: auto;
  }


  /* ---- Footer, Figma frame 3116:689 (page 5305 -> 5926) ------------------ */
  /* Rebuilt to the frame. Coordinates below are the frame's own, less 5305 —
     where the footer background begins — so the whole block is measured from
     one origin instead of from the page. The bar runs 5870 -> 5926, so
     anything pinned to it is the frame number less 5870. */
  .contact {
    height: calc(565 * var(--u));
    padding: 0;
    overflow: hidden;
  }

  /* The same flat export as the hero, this way up, scaled and pushed left
     inside a box exactly the frame's width. */
  .contact::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: calc(396 * var(--u));
    height: calc(621 * var(--u));
    background: url("../assets/img/footer-flat-ink.webp") no-repeat;
    background-size: calc(887.2 * var(--u)) calc(621 * var(--u));
    background-position: calc(-491.1 * var(--u)) 0;
    pointer-events: none;
  }

  /* LET'S TALK, two lines, grown to match the hero. */
  .display--talk {
    left: calc(50% - 2.5 * var(--u));
    top: calc(180 * var(--u));
    font-size: calc(174.404 * var(--u));
    letter-spacing: calc(-8.7202 * var(--u));
    line-height: 0.83;
    white-space: normal;
    width: calc(393 * var(--u));
    /* Its own fade, not the desktop's. The 1920 frame runs 2.2433 / 56.671 /
       80.621 off a 179.516deg axis; the 393 frame is straight down and holds
       full white much longer — 0 / 73.175 / 105.37, so the second line is
       still legible where the desktop would already have faded it out. */
    background-image: linear-gradient(to bottom,
      rgb(255, 255, 255) 0%,
      rgba(255, 255, 255, 0.5) 73.175%,
      rgba(255, 255, 255, 0) 105.37%);
  }

  /* The CTA is not in the mobile frame. .contact__outro stays — it is the
     wrapper the LET'S TALK wordmark lives inside, and hiding it took the
     wordmark with it. */
  .contact__cta { display: none; }

  .contact__outro {
    position: static;
    width: auto;
    font-size: 0;   /* the wrapper carries no copy of its own on mobile */
  }

  /* Four hairlines again, flipped: 73/154/234/315, each starting a little
     above the band. Reusing the quotes band, which the mobile layout has no
     other use for.

     ANCHORED FROM THE BOTTOM, and that is the whole point of this rule. It
     used to carry a page-y (top: 6818) which had to be re-pinned by hand
     every single time a section above it changed height — seven times, and
     it was 1776 out of place by the time anyone measured it, sitting inside
     the white band where white lines are invisible. The frame runs the band
     5048 -> 5925 against a page ending 5926, and .grid-lines stops at the
     top of the bar (5870), so its bottom is 55 past that — a number nothing
     above it can move. */
  .grid-lines__band--quotes {
    display: block;
    left: 0;
    width: calc(393 * var(--u));
    top: auto;
    bottom: calc(-55 * var(--u));
    /* 877 was the frame's own band, which began level with the contact block.
       She wants the rain to start higher, at the top of Reviews: measured from
       there down to this band's bottom is 1510. Still bottom-anchored, so only
       a change in the Reviews section's own height can move it.
       --band-h has to follow, or the drops fall 1068 through a 1510 band and
       the lower third never gets wet. */
    height: calc(1510 * var(--u));
    --band-h: calc(1510 * var(--u));
  }

  .grid-lines__band--quotes span:nth-child(1) { left: calc(73 * var(--u)); top: calc(22 * var(--u)); }
  .grid-lines__band--quotes span:nth-child(2) { left: calc(154 * var(--u)); top: 0; }
  .grid-lines__band--quotes span:nth-child(3) { left: calc(234 * var(--u)); top: 0; }
  /* The desktop hides this one, where it would fall between two testimonial
     columns. There are no columns here and the frame wants four. */
  .grid-lines__band--quotes span:nth-child(4) {
    display: block;
    left: calc(315 * var(--u));
    top: calc(47 * var(--u));
  }

  /* ---- The bar ---------------------------------------------------------- */
  /* The frame does not stop the picture at the bar — node 3128:349 is 621
     tall from 5305, and the bar (5870, 56 tall) sits ON it at 60% dark. The
     .contact::before above clips at 565 because the section does, so the last
     56 of the same image is carried here as the bottom layer, shifted 565 up
     inside it, with the bar colour as a flat wash over it. Same numbers as
     .contact::before, one origin. */
  .site-footer {
    position: relative;
    height: calc(56 * var(--u));
    min-height: 0;
    padding: 0;
    display: block;
    background:
      linear-gradient(rgba(13, 9, 20, 0.6), rgba(13, 9, 20, 0.6)),
      url("../assets/img/footer-flat-ink.webp")
        calc(-491.1 * var(--u)) calc(-565 * var(--u)) / 
        calc(887.2 * var(--u)) calc(621 * var(--u)) no-repeat;
    border-top: 1px solid rgba(159, 147, 255, 0.4);
  }

  .site-footer__copy {
    position: absolute;
    left: calc(50% - 0.5 * var(--u));
    top: calc(19 * var(--u));
    translate: -50%;
    font-size: calc(12 * var(--u));
    line-height: 1.3;
    white-space: nowrap;
  }

  /* The legal links and the icons sit ABOVE the bar, in the band, so they are
     lifted out of the footer's own box by a negative offset. */
  /* The frame gives each link a 30-tall text box at 10/2.16 and steps the
     boxes 15 apart, so what is actually 15 apart is the line of type in the
     middle of each box — 2.16 leading would set them 21.6 apart. Line-height
     1.5 makes the box the step, and the first line then centres on 5817,
     which is 60.5 above the bar.

     flex, not block: the markup order is a11y / terms / privacy and the frame
     reads a11y / privacy / terms. The `order` values below already say so and
     were inert on a block box. */
  .site-footer__links {
    position: absolute;
    display: flex;
    flex-direction: column;
    right: calc(36 * var(--u));
    top: calc(-60.5 * var(--u));
    text-align: right;
  }

  .site-footer__link {
    display: block;
    font-size: calc(10 * var(--u));
    line-height: 1.5;   /* the frame's 15 step; see above */
    white-space: nowrap;
  }

  .site-footer__link--a11y    { order: 1; }
  .site-footer__link--privacy { order: 2; }
  .site-footer__link--terms   { order: 3; }

  .site-footer__social {
    position: absolute;
    left: calc(36 * var(--u));
    top: calc(-63 * var(--u));
    display: flex;
    flex-direction: column;
    gap: calc(4.76 * var(--u));
  }

  .site-footer__social img,
  .site-footer__social a {
    width: calc(11.171 * var(--u));
    height: calc(11.171 * var(--u));
  }


  /* ======================================================================
     1:1 pass — every section placed against the mobile frame (3116:689)
     ----------------------------------------------------------------------
     The frame is one 393 x 5926 artboard. Sections here are given the exact
     heights that make each page coordinate in it land where it lands, so a
     number below can be read straight off the frame minus the section's own
     start. The map:

       hero          0    ->  696
       why           696  -> 1529   (white band 1, its own carved top)
       projects      1529 -> 2934
       about         2934 -> 3710
       everything    3710 -> 4512   (white band 2, a DIFFERENT carved top)
       testimonials  4512 -> 5305
       contact       5305 -> 5870
       footer        5870 -> 5926
     ====================================================================== */

  /* Heights come from the CONTENT, not from the frame. The frame carries a
     short placeholder in every card and one short testimonial; the real text
     runs two to three times longer, and pinned to the frame's Y positions it
     simply piled on top of itself. What transfers from the frame is the
     spacing — how far the first card sits from the section top, how wide
     things are, the type sizes — not where each item lands on the artboard. */
  .why          { height: auto; padding: calc(201 * var(--u)) 0 calc(96 * var(--u)); }
  /* The -24 is a correction, not a design number. .why measures exactly 833
     and ends exactly where it should, .projects carries no margin, and there
     is nothing between them but whitespace — yet the two sit 24 apart, and
     that error then shifts every section below. Pulled back explicitly so the
     rest of the page can be read straight off the frame. */
  .projects     { height: auto; padding: calc(142 * var(--u)) 0 calc(48 * var(--u)); }
  .about        { height: auto; padding: calc(111 * var(--u)) 0 calc(72 * var(--u)); }
  .everything   { height: auto; padding: calc(165 * var(--u)) 0 calc(96 * var(--u)); }
  .testimonials { height: auto; padding: calc(77 * var(--u)) 0 calc(72 * var(--u)); }

  /* Band 1: M393 833V0 L250.5 118.5 H158.5 L0 71.5 */
  .why {
    clip-path: polygon(100% 0, 63.74% calc(118.5 * var(--u)),
      40.33% calc(118.5 * var(--u)), 0 calc(71.5 * var(--u)), 0 100%, 100% 100%);
  }

  /* Band 2: M393 802V0 L257 29 L154 24 L0 82.5 — a shallower notch, tipped
     the other way. The two are not the same shape. */
  .everything {
    clip-path: polygon(100% 0, 65.39% calc(29 * var(--u)),
      39.19% calc(24 * var(--u)), 0 calc(82.5 * var(--u)), 0 100%, 100% 100%);
  }

  /* ---- Why Me ---------------------------------------------------------- */
  /* margin:0 matters — the desktop gives this a -77.5 margin-top to pull the
     block up under the wave, and absolute positioning does not cancel it. */
  .why__inner {
    position: static;
    margin: 0 auto;
    translate: none;
    width: calc(325 * var(--u));
    gap: calc(20 * var(--u));
  }

  /* height:auto matters — the desktop gives the row a fixed height for the
     mosaic, and stacked that surplus opened as a 110 gap between the first two
     cards while the third sat 20 away. */
  .why__row {
    gap: calc(20 * var(--u));
    height: auto;
    justify-content: flex-start;
  }

  .why__row .card { margin-bottom: 0; }

  /* Flush with the deck, top and bottom: the wordmark's ink and the finished
     stack are both 516.7 tall and start together. Measured against the stage
     now rather than the section, so 0 is the top of card 01 — and the wrapper
     goes to -21.6 because the rotated span renders that far BELOW its box at
     this size. Re-measure that offset whenever the font-size above changes; it
     does not scale with it. */
  /* -20, not -60. At -60 the wordmark ran from x -52.3, so 37% of it was off
     the left edge and the letterforms were sliced lengthwise — cut through the
     middle of the type rather than at its edge. -20 leaves 12.3 outside, which
     reads as a wordmark running off the screen instead of a broken one. */
  .why .display--why { left: calc(-20 * var(--u)); top: calc(-21.6 * var(--u)); }

  /* ---- Projects -------------------------------------------------------- */
  .display--projects {
    top: calc(-17 * var(--u));
    left: calc(50% + 26 * var(--u));
    font-size: calc(165.931 * var(--u));
    letter-spacing: calc(-3.3186 * var(--u));
  }

  .projects__sets { position: static; width: 100%; }
  .projects__grid { gap: 0; }

  /* 424 from one tile to the next: 347 of tile, 12 to the caption, 65 of air. */
  .projects .tile { margin-bottom: calc(12 * var(--u)); }
  .tile-caption   { margin-bottom: calc(53 * var(--u)); }

  .projects__cta { margin-top: calc(24 * var(--u)); }

  /* ---- Soft blur under the projects ------------------------------------
     ONE shape, not two. There were two — one low in the band and one on the
     CTA — and at 300 and 250 wide sitting 200 apart they read as a pair of
     spots rather than as light. The second is deleted and this one is grown
     to 480 x 420 with the core alpha down from 0.34 to 0.19 and the tail
     stretched, so the same amount of glow is spread over more than twice the
     area and has no edge anywhere.

     Painted as a radial gradient, NOT filter: blur(). A blur is the obvious
     way to write this and it is the one thing this page has been burned by:
     a filter puts its element on a texture of its own, and a 45 blur around a
     480 box is a 570x510 CSS layer — about 15MB at 3x, for decoration.
     Three stops with a long tail give the same out-of-focus falloff for
     nothing.

     Behind everything the section holds (z-index 0 against the content 1). */
  .projects::before {
    content: "";
    position: absolute;
    border-radius: 50%;
    pointer-events: none;
    z-index: 0;
    left: calc(-120 * var(--u));
    bottom: calc(70 * var(--u));
    width: calc(480 * var(--u));
    height: calc(420 * var(--u));
    background: radial-gradient(closest-side,
                rgba(159, 147, 255, 0.19), rgba(159, 147, 255, 0.11) 38%,
                rgba(159, 147, 255, 0.04) 68%, rgba(159, 147, 255, 0) 100%);
  }

  .projects__cta { position: relative; top: auto; }

  /* ---- About ----------------------------------------------------------- */
  .display--about {
    top: 0;
    left: calc(50% - 2.7 * var(--u));
    font-size: calc(216.024 * var(--u));
    letter-spacing: calc(-4.3205 * var(--u));
  }

  /* ABOUT rather than ABOUT ME — main.js shortens it behind this same media
     query, because the desktop is signed off saying ABOUT ME. Five letters do
     not fill 393 at the size eight did, so the size is set from the width it
     has to span rather than from the frame. */
  .about .display--about {
    font-size: calc(205 * var(--u));
    letter-spacing: calc(-4.1 * var(--u));
    white-space: nowrap;
  }

  .about__inner {
    position: static;
    margin: 0 auto;
    translate: none;
    width: calc(321 * var(--u));
    gap: calc(30 * var(--u));
  }

  /* column-reverse, not block: the markup has the name before the photo (the
     desktop reads them left to right on one line), and the frame wants the
     photo above. */
  .about__head {
    display: flex;
    flex-direction: column-reverse;
    align-items: center;
    gap: 0;
    margin: 0;
    text-align: center;
  }

  .about__photo {
    width: calc(96.608 * var(--u));
    height: calc(96 * var(--u));
    margin: 0 auto calc(15 * var(--u));
    border-width: calc(1.215 * var(--u));
  }

  .about__name {
    font-size: calc(64 * var(--u));
    line-height: 0.98;
    margin-bottom: calc(30 * var(--u));
  }

  .about__bio { width: calc(321 * var(--u)); text-align: center; }

  /* ---- The About wave, mobile ------------------------------------------
     Its own asset now: wave-about-mobile.png, exported from the 393 frame at
     393x313 with the rotation and the crop already baked in. No transform, no
     object-fit trickery, no re-derivation of a rotated bounding box — the
     picture IS the frame slice, so it is placed 1:1.

     Anchored from the BOTTOM of the section rather than by a fixed top: the
     real bio runs longer than the frame placeholder, so any absolute y taken
     from the band start lands in the wrong place. In the frame the box top
     sits exactly on the CTA top and the box is 313 tall, so 313 minus (41 of
     button + 26.6 of tail) put its bottom 243 below the section end — but the
     wave belongs on the dark/white seam, not on the button, so it is raised to
     189: the ink (y 84–246 in the file) then centres 41 below the boundary,
     which is where the frame has it (ink 3670–3832 against a band ending 3710).
     The ink inside the file runs y 84–246, which is what keeps it clear of
     the button and lets it hang into the section below, as the frame has it. */
  .wave--about {
    display: block;
    left: 0;
    top: auto;
    bottom: calc(-189 * var(--u));
    width: 100%;
    height: calc(313 * var(--u));
    transform: none;
    object-fit: fill;
    object-position: center;
    clip-path: none;
  }

  /* ---- The About CTA, off the 393 frame (node 3131:426) ----------------
     318 wide, 8/36 padding, a 100 radius on #9F93FF, 16px at 1.591 — a pill,
     like every other CTA on the site. The purple is not on background-color
     but on .btn--solid's ::before, which is how the hover fill gets something
     to mask; that is by design, not a missing colour.

     The frame pins it at 651 of the About band and that number is NOT used.
     Its bio is the real copy but sets 16 lines where ours sets more, so 651
     lands inside our text — the same trap the desktop's fixed offset fell
     into. In the flow instead, spaced by .about__inner's own 30 gap, which is
     the rhythm the rest of the section already uses. */
  /* position: relative, NOT static. .btn is relative in style.css and its
     ::before — the purple fill, position:absolute inset:-1px — is anchored to
     it. Made static, that ::before escapes to .about and paints a rounded
     purple rectangle the size of the whole section: the full-screen panel.
     Kept out of the desktop flow with inset:auto instead, which leaves it in
     the flow without giving the pseudo-element anything to inherit. */
  .about .btn--xl {
    display: flex;
    position: relative;
    inset: auto;
    width: calc(318 * var(--u));
    padding: calc(8 * var(--u)) calc(36 * var(--u));
    margin: 0 auto;
    translate: none;
    border-radius: calc(100 * var(--u));
    font-size: calc(16 * var(--u));
    line-height: 1.591;
  }

  /* ---- Everything you need --------------------------------------------- */
  .everything__inner {
    position: static;
    margin: 0 auto;
    translate: none;
    width: calc(325 * var(--u));
    gap: calc(20 * var(--u));
  }

  .everything__col { gap: calc(20 * var(--u)); height: auto; justify-content: flex-start; }
  .everything__inner > .card--side,
  .everything__col .card { margin-bottom: 0; }

  /* Beside the deck, reading downwards, exactly as WHY ME is — and now on the
     same parked stage, so `top` is measured from the top of card 01.

     The translate before the rotation is the whole fix. rotate(90deg) about a
     left-top origin swings the box to the LEFT of its own left edge, so at
     left:-60 this wordmark was sitting at x -254 to -60: entirely off the
     screen, which is where it had been all along. Moving it back along the
     rotated y axis by its own height puts it at x -60 to +79 instead, the same
     sliver of it showing as WHY ME shows.

     The size is set from the deck: the text has to run 516.7 down the page to
     finish level with the last card. */
  .everything .display--everything {
    left: calc(-20 * var(--u));   /* same 40 to the right as WHY ME, same reason */
    top: 0;
    width: auto;
    transform: rotate(90deg) translateY(-100%);
    transform-origin: left top;
    font-size: calc(136.4 * var(--u));
    letter-spacing: calc(-2.728 * var(--u));
    white-space: nowrap;
  }

  /* ---- The header, off the 393 frame ------------------------------------
     Figma 3179:434 / 3179:515 / 3179:531 — the same three grounds as the
     desktop, in a 321 capsule at 13 from the top. Order across the row is
     menu, logo, CTA, which in an RTL flex row is the DOM order as written.

     The blur she put on all three is deliberately not here — see the note on
     the desktop rule. 70% already reads as frosted, and a backdrop-filter on
     a fixed element is what painted the purple screen on her phone. */
  .site-head {
    left: 50%;
    translate: -50%;
    width: calc(321 * var(--u));
    top: calc(13 * var(--u));
    padding: calc(6 * var(--u)) calc(10 * var(--u)) calc(6 * var(--u)) calc(6 * var(--u));
  }

  .site-head__nav { display: none; }

  .site-head__menu {
    display: block;
    flex: none;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    cursor: pointer;
    line-height: 0;
  }

  .site-head__menu-svg {
    display: block;
    width: calc(82 * var(--u));
    height: calc(23.5 * var(--u));
  }

  /* The desktop wraps the wordmark in a 147 box with the art pushed to its
     outer edge, because on the 1920 frame that empty space is what positions
     the four links. There is no nav here and the capsule is 321 wide, so that
     box has to be undone or it eats half the row and pushes the CTA out
     through the padding. Undone explicitly, not by luck. */
  .site-head__logo {
    display: block;
    width: auto;
  }

  /* 57.876 x 19.17 — the same artwork as the desktop at 3.019:1, so it is the
     same inlined file at a smaller size rather than a second asset. */
  .site-head__logo-svg {
    margin-left: 0;
    translate: 0 calc(-1.5 * var(--u));
    width: calc(57.876 * var(--u));
    height: calc(19.17 * var(--u));
  }

  /* 14 type, 12/4 padding, and the label is "שנתחיל?" here rather than the
     desktop's "בואו נתחיל" — swapped in main.js behind this media query. */
  .site-head__cta {
    width: auto;
    font-size: calc(14 * var(--u));
    padding: calc(4 * var(--u)) calc(12 * var(--u));
  }

  /* ---- The menu sheet ---------------------------------------------------
     Hangs under the capsule, same width, same radius, and wears whichever of
     the three grounds the capsule is wearing. It grows out of the header
     rather than sliding over the page: scaled from 96% and lifted 8, with the
     four links fading in one after another so it unfolds instead of appearing.

     [hidden] is removed before the frame the class lands on, so there is
     something for the transition to run from. */
  .site-menu {
    display: flex;
    flex-direction: column;
    position: fixed;
    left: 50%;
    translate: -50%;
    /* 13 of top + 44 of capsule + 8 of air. A percentage would resolve
       against the viewport, not the header, because both are fixed. */
    top: calc(65 * var(--u));
    width: calc(321 * var(--u));
    padding: calc(14 * var(--u)) calc(24 * var(--u));
    gap: calc(16 * var(--u));
    z-index: 149;

    border-radius: calc(24 * var(--u));
    background: rgba(255, 255, 255, 0.2);
    color: var(--c-white);

    opacity: 0;
    scale: 0.96;
    transform-origin: 50% 0;
    pointer-events: none;
    transition: opacity 0.28s var(--ease-out),
                scale 0.28s var(--ease-out),
                background-color 0.7s var(--ease-soft),
                color 0.7s var(--ease-soft);
  }

  .site-menu.is-open {
    opacity: 1;
    scale: 1;
    pointer-events: auto;
  }

  .site-menu a {
    font-size: calc(18 * var(--u));
    line-height: 1.4;
    font-weight: var(--fw-light);
    color: inherit;
    text-align: right;
    opacity: 0;
    translate: 0 calc(-6 * var(--u));
    transition: opacity 0.3s var(--ease-out), translate 0.3s var(--ease-out);
  }

  .site-menu.is-open a { opacity: 1; translate: 0; }
  .site-menu.is-open a:nth-child(1) { transition-delay: 0.06s; }
  .site-menu.is-open a:nth-child(2) { transition-delay: 0.11s; }
  .site-menu.is-open a:nth-child(3) { transition-delay: 0.16s; }
  .site-menu.is-open a:nth-child(4) { transition-delay: 0.21s; }

  /* The sheet follows the capsule, and takes the same hairline for the same
     reason: over .why and .everything a 70% white fill on pure white has no
     edge of its own. */
  .site-head.is-solid ~ .site-menu {
    background: rgba(255, 255, 255, 0.7);
    color: var(--c-dark);
    border: 1px solid rgba(13, 9, 20, 0.10);
  }

  .site-head.is-solid ~ .site-menu a { font-weight: var(--fw-reg); }

  /* ---- Reviews, off the 393 frame ---------------------------------------
     Frame numbers, all measured from the top of the band (4512):
       REVIEWS wordmark  4496  ->  -16, 162.549 / -3.251
       מה אומרים עלי?    4589  ->   77, Cooperative 64 / 0.98
       row 1             4699  ->  187, cards at x -32 and 199
       row 2             4991  ->  479, cards at x -147, 84 and 316
       card              219 wide, 20 padding, 12 radius, 0.5 hairline,
                         26 between avatar, quote and name; avatar 70 x 68
     Rows 292 apart and cards 231 apart across (219 + a 12 gutter). Running
     off both edges at once is the whole tell: this is a marquee caught
     mid-travel, not a two-column grid. */
  .display--testimonials {
    display: block;
    top: calc(-16 * var(--u));
    left: calc(50% - 2.9 * var(--u));
    font-size: calc(162.549 * var(--u));
    letter-spacing: calc(-3.251 * var(--u));
  }

  .testimonials__kicker {
    position: relative;
    z-index: 1;
    top: auto;
    left: auto;
    right: auto;
    translate: none;
    text-align: center;
    font-size: calc(64 * var(--u));
    line-height: 0.98;
    margin: 0;
  }

  /* The wall becomes two stacked rows. No mask: the frame cuts the cards
     hard at the screen edge, it does not fade them. */
  .quotes {
    position: relative;   /* z-index 1, above .testimonials::after */
    z-index: 1;
    top: auto;
    left: auto;
    right: auto;
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
    -webkit-mask-image: none;
            mask-image: none;
    margin-top: calc(47 * var(--u));   /* 110 from the kicker top, less its 63 of ink */
  }

  /* A column is a ROW here, and its own window. width:100% + overflow:hidden
     is what cuts the cards at both edges; the track inside is wider than the
     screen and always will be. */
  .quotes__col {
    display: block;
    width: 100%;
    height: auto;
    overflow: hidden;
    transform: none;
  }

  /* 292 between the rows in the frame, of which 282 is the card. */
  .quotes__col + .quotes__col { margin-top: calc(10 * var(--u)); }

  /* Emptied by main.js — its three testimonials are dealt into the two rows
     above rather than dropped. */
  .quotes__col:nth-child(3) { display: none; }

  .quotes__track {
    flex-direction: row;
    align-items: stretch;
    width: max-content;
    gap: calc(12 * var(--u));
  }

  /* Sideways instead of upwards. --loop is one set of cards plus its gutters,
     measured across in js/marquee.js; translating by exactly that hides the
     seam. The second row is the same animation played backwards, so the two
     never read as one block sliding, and the negative delays start each row
     part-way in rather than on a card edge — which is what the frame shows. */
  .quotes.is-running .quotes__track {
    animation: quotes-side var(--speed, 30s) linear infinite;
    animation-delay: -2s;
  }

  .quotes.is-running .quotes__col:nth-child(2) .quotes__track {
    animation-direction: reverse;
    animation-delay: -7s;
  }

  @keyframes quotes-side {
    to { transform: translateX(calc(-1 * var(--loop, 0px))); }
  }

  .quote {
    flex: none;
    width: calc(219 * var(--u));
    padding: calc(20 * var(--u));
    border-radius: calc(12 * var(--u));
    font-size: calc(16 * var(--u));
  }

  /* Clamped to the frame's card. 282 is 40 of padding, 68 of avatar, two 26
     gaps, 19 of name — and FIVE lines of quote at 16/1.3. The real quotes run
     two to five paragraphs, so without this the rows came out 475 and 736.

     -webkit-box, not flex: line-clamp only works on a box, and the flex gap
     goes with it, so the paragraph spacing comes back as a margin. */
  .quote blockquote {
    font-size: calc(16 * var(--u));
    line-height: 1.3;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 5;
    overflow: hidden;
  }

  .quote blockquote p { margin: 0 0 calc(6 * var(--u)); }
  .quote blockquote p:last-child { margin-bottom: 0; }

  .quote.is-open blockquote {
    -webkit-line-clamp: unset;
    overflow: visible;
  }

  /* .quote is an rtl column with a 26 gap, which is the right distance
     between the avatar, the quote and the name but far too much under a link
     that belongs to the paragraph above it. Pulled back to 8.
     align-self:flex-start reads as the RIGHT edge inside the rtl card — the
     same reason the avatar uses it. */
  .quote__more {
    align-self: flex-start;
    margin-top: calc(-18 * var(--u));
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: calc(15 * var(--u));
    color: var(--c-purple-light);
    text-decoration: underline;
    text-underline-offset: 0.25em;
    cursor: pointer;
  }

  /* Reading beats moving: a row with an open card stops until it is closed. */
  .quotes.is-running .quotes__col.is-paused .quotes__track {
    animation-play-state: paused;
  }
  .quote figcaption { font-size: calc(16 * var(--u)); }
  .quote__avatar { width: calc(70 * var(--u)); height: calc(68 * var(--u)); }

  /* ---- The project viewer ----------------------------------------------
     393 is not 1920: title, counter, zoom readout and five buttons in one bar
     leaves nothing room to breathe. The two readouts go — the zoom buttons
     still say what they do and the arrows still step through the set, so
     nothing becomes unreachable, only unlabelled.
     The counter carried margin-inline-end:auto, which is what pushed the
     controls to the far side, so the title takes that job over. */
  .project-viewer__pct,
  .project-viewer__count { display: none; }

  .project-viewer__title { margin-inline-end: auto; }

  .project-viewer__bar {
    gap: calc(8 * var(--u));
    padding: calc(8 * var(--u)) calc(10 * var(--u));
  }

  /* ---- Contact --------------------------------------------------------- */
  /* It IS in the frame after all — 236 wide at 5359, above LET'S TALK. */
  .contact__cta {
    display: inline-flex;
    position: absolute;
    left: calc(50% + 0.5 * var(--u));
    top: calc(54 * var(--u));
    translate: -50%;
    width: calc(236 * var(--u));
    font-size: calc(16 * var(--u));
  }

}

/* ==========================================================================
   5 Oct 2026 — the phone after the desktop changes (her call: "go through it
   patiently and fix everything")
   ========================================================================== */
@media (max-width: 899px) {
  /* HERO. js/site-degolan.js turns WEB / DESIGN into Degolan at Cooperative's
     WIDTH — and Degolan is taller for its width, so DESIGN ran down over
     "Made For Developers" and the mark. A size that keeps the Cooperative
     block's height (the frame's 3123 layout below it then holds). */
  .display.display--hero { font-size: calc(200 * var(--u)) !important; }
  /* its foot is at 418 now: the label + mark 20 lower, the words with them */
  .hero__badge { top: calc(432 * var(--u)); }
  .hero__mark  { top: calc(422 * var(--u)); }   /* centred on the label (432 + 9 - 19) */
  .hero__copy  { top: calc(528 * var(--u)); }
  .hero        { height: calc(716 * var(--u)); }
}

@media (max-width: 899px) {
  /* ABOUT — the mentoring page's About (this section is its copy), laid out
     as that page's phone has it (css/mentoring-mobile.css): the whole photo
     fading into the dark, the name lifted onto it, the words centred, the
     button the width of the column. */
  .about.about--m {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    height: auto;
    padding: calc(60 * var(--u)) calc(24 * var(--u)) calc(90 * var(--u));
  }
  .about--m > * { position: relative; left: auto; top: auto; right: auto; translate: none; }
  .about--m .wave--about { position: absolute; }
  .abm__photo {
    width: 100%;
    height: auto;
    aspect-ratio: 1159 / 1356;
    overflow: hidden;
    opacity: 1;
    -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent 96%);
            mask-image: linear-gradient(to bottom, #000 55%, transparent 96%);
  }
  .abm__photo img { position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 0; }
  .abm__name {
    z-index: 2;
    width: auto;
    margin: calc(-92 * var(--u)) 0 0;
    font-size: calc(44 * var(--u));
    line-height: 1.05;
    text-align: center;
    white-space: normal;
  }
  .about--m .about__bio.abm__bio {
    width: auto;
    max-width: none;
    margin: calc(24 * var(--u)) 0 0;
    font-size: calc(16 * var(--u));
    line-height: 1.55;
    text-align: center;
  }
  .about--m .abm__cta {
    display: flex;
    justify-content: space-between;
    width: 100%;
    margin-top: calc(28 * var(--u));
    padding: calc(12 * var(--u)) calc(24 * var(--u));
    font-size: calc(18 * var(--u));
  }

  /* CONTACT — the two buttons stacked, the column's width, one size */
  .contact__ctas {
    flex-direction: column;
    align-items: stretch;
    gap: calc(12 * var(--u));
    width: calc(321 * var(--u));
  }
  .contact__ctas .btn { width: 100%; font-size: calc(18 * var(--u)); padding: calc(12 * var(--u)) calc(24 * var(--u)); }
}
@media (max-width: 899px) {
  /* the two buttons above LET'S TALK, clear of it (the frame had none here;
     her call, 5 Oct: both, as the desktop) */
  .contact__ctas { top: calc(32 * var(--u)); }
  .contact__ctas .contact__cta { display: flex; }
  .contact { height: calc(589 * var(--u)); }
  .display--talk { top: calc(204 * var(--u)); }
}

/* ==========================================================================
   HER PHONE NOTES, 5 Oct 2026 (round 1) — the phone only
   ========================================================================== */
@media (max-width: 899px) {
  /* ---- THE WAVES = the mentoring page's ribbon, in its phone pose --------
     The hero's <img> still carried the OLD wave's box (1472 x 1032) with the
     ribbon file in it: stretched, turned and running through the words and
     buttons. Now drawn as on mentoring.html — on .hero::after / .about::after
     — and the white band under each is cut along the ribbon's centre line
     (js/index-waves.js), so the edge between dark and white IS the wave. */
  .waves, .about--m .wave--about { display: none; }
  .hero { z-index: 3; }
  .hero::after {
    content: "";
    position: absolute;
    left: calc(50% - 880 * var(--u));
    bottom: calc(-335 * var(--u));
    width: calc(1300 * var(--u));
    height: calc(297 * var(--u));
    background: url("../assets/img/mentoring/wave-ribbon.webp") no-repeat 0 0 / 100% 100%;
    transform: rotate(-12deg);
    pointer-events: none;
  }
  /* the second, smaller (her note), over About's foot and the white below */
  .about.about--m { position: relative; z-index: 3; }
  .about.about--m::after {
    content: "";
    position: absolute;
    left: calc(50% - 560 * var(--u));
    bottom: calc(-215 * var(--u));
    width: calc(840 * var(--u));
    height: calc(192 * var(--u));
    background: url("../assets/img/mentoring/wave-ribbon.webp") no-repeat 0 0 / 100% 100%;
    transform: rotate(-3deg);
    pointer-events: none;
  }

  /* ---- PROJECTS / TESTIMONIALS: the wordmark's top was under the white
     band above (the frame starts them 17 / 16 above their band). Down into
     their own band; what follows moves down with them ---------------------- */
  .display--projects { top: calc(52 * var(--u)) !important; }
  .projects { padding-top: calc(212 * var(--u)) !important; }
  .display--testimonials { top: calc(52 * var(--u)) !important; }
  .testimonials { padding-top: calc(170 * var(--u)) !important; }   /* מה אומרים עליי? lower (her note) */

  /* ---- EVERYTHING: the wordmark ran down the side, cut lengthwise. Lying
     flat over the deck, whole, the screen's width -------------------------- */
  .everything { padding-top: calc(300 * var(--u)) !important; }
  .everything .display--everything {
    left: 50% !important;
    top: calc(-178 * var(--u)) !important;
    translate: -50% 0 !important;
    transform: none !important;
    width: auto !important;
    font-size: calc(170 * var(--u)) !important;
    letter-spacing: calc(-3.4 * var(--u)) !important;
    white-space: nowrap;
  }

  /* ---- the footer: bigger contact icons and legal links (her note) ----- */
  .site-footer__link { font-size: calc(13 * var(--u)); }
  .site-footer__links { top: calc(-74 * var(--u)); }
  .site-footer__social { top: calc(-40 * var(--u)); flex-direction: row; gap: calc(16 * var(--u)); }
  .site-footer__social img, .site-footer__social a { width: calc(18 * var(--u)); height: calc(18 * var(--u)); }
}
@media (max-width: 899px) {
  /* LET'S TALK on ONE line, the screen's width (her note, 5 Oct, all pages) */
  .display--talk {
    width: calc(393 * var(--u)) !important;
    font-size: calc(207 * var(--u)) !important;
    letter-spacing: -0.02em !important;
    line-height: 0.87 !important;
    white-space: nowrap !important;
  }
}
@media (max-width: 899px) {
  /* one line of LET'S TALK: the band shorter, no empty band under it */
  .contact { height: calc(480 * var(--u)) !important; }
}

/* LET'S TALK — her frame 3749:891 (5 Oct 2026): Degolan 198.737, line 0.83,
   468.344 wide (the L and the K run off the screen), its top 95 above the
   bar, fading down to it. The legal links and the icons move ABOVE it, centred. */
@media (max-width: 899px) {
  .display--talk {
    top: calc(403 * var(--u)) !important;           /* its line 95 above the bar (measured) */
    left: 50% !important;
    width: calc(468.344 * var(--u)) !important;
    font-size: calc(198.737 * var(--u)) !important;
    letter-spacing: 0 !important;
    line-height: 0.83 !important;
    background-image: linear-gradient(180.59deg, #FFFFFF 1.2263%, rgba(255, 255, 255, 0.5) 60.162%, rgba(255, 255, 255, 0) 79.543%) !important;
  }
  .site-footer__links {
    top: calc(-134 * var(--u)) !important;
    right: auto !important;
    left: 50% !important;
    translate: -50% 0;
    flex-direction: row !important;
    gap: calc(18 * var(--u));
  }
  .site-footer__social {
    top: calc(-172 * var(--u)) !important;
    left: 50% !important;
    translate: -50% 0;
    flex-direction: row !important;
    gap: calc(22 * var(--u)) !important;
  }
  .site-footer__social img, .site-footer__social a { width: calc(20 * var(--u)) !important; height: calc(20 * var(--u)) !important; }
}
@media (max-width: 899px) {
  /* a whole Degolan wordmark: its room above (css/site-nav.css .is-whole) on
     top of the ink correction js/site-degolan.js writes inline (-0.0903em) */
  html[data-titles-phone] .is-degolan.is-whole { margin-top: calc(-0.0903em - 0.25em) !important; }
}
@media (max-width: 899px) {
  /* LET'S TALK ends ON the line (her note): the type box 164.95 tall, its foot on the bar */
  .display--talk { top: calc(333 * var(--u)) !important; }
}
@media (max-width: 899px) {
  /* LET'S TALK on the line (its top 165 above the bar): the links and icons above it */
  .site-footer__links { top: calc(-207 * var(--u)) !important; }
  .site-footer__social { top: calc(-245 * var(--u)) !important; }
}
@media (max-width: 899px) {
  /* HERO, her note (6 Oct): the title a little higher, less air before
     "היי, אני צביה", all of it in the first screen and not down on its foot:
     title / label / mark -20, the words and buttons -57, the hero (and the
     wave and the white under it) -57 with them */
  .display.display--hero { top: calc(85 * var(--u)) !important; }
  .hero__badge { top: calc(412 * var(--u)) !important; }
  .hero__mark  { top: calc(402 * var(--u)) !important; }
  .hero__copy  { top: calc(471 * var(--u)) !important; }
  .hero        { height: calc(659 * var(--u)) !important; }
}
@media (max-width: 899px) {
  /* her notes, 6 Oct ---------------------------------------------------- */
  /* WHY ME, lighter on the white */
  .why .display--why > span {
    background-image: linear-gradient(to top,
      rgba(105, 94, 190, 0.11) 15.879%,
      rgba(105, 94, 190, 0.065) 109.35%,
      rgba(105, 94, 190, 0.03) 149.21%);
  }
  /* PROJECTS / REVIEWS: their letters on the thin purple line (were 50 below) */
  .display--projects { top: calc(3 * var(--u)) !important; }
  .projects { padding-top: calc(163 * var(--u)) !important; }
  .display--testimonials { top: calc(3 * var(--u)) !important; }
  .testimonials { padding-top: calc(121 * var(--u)) !important; }
  /* EVERYTHING: the screen's width, its foot a little under the first card */
  .everything .display--everything { font-size: calc(179 * var(--u)) !important; top: calc(-110 * var(--u)) !important; }
  /* LET'S TALK: its letters' foot on the purple line (was 7 above) */
  .display--talk { top: calc(340.3 * var(--u)) !important; }
}
@media (max-width: 899px) {
  .everything .display--everything { top: calc(-124 * var(--u)) !important; }   /* its foot 13 under the first card */
  .everything { padding-top: calc(312 * var(--u)) !important; }                  /* its letters clear of the wave's cut (174 at the left edge) */
}
@media (max-width: 899px) {
  .display--projects, .display--testimonials { top: calc(4.5 * var(--u)) !important; }   /* on the line at every width (430: was 1 over it) */
}
@media (max-width: 899px) {
  /* LET'S TALK touching the line: the fade ends at the letters' foot (97.5%), not at 79.5% */
  .display--talk { background-image: linear-gradient(180.59deg, #FFFFFF 1.5%, rgba(255, 255, 255, 0.5) 73.8%, rgba(255, 255, 255, 0) 97.5%) !important; }
}
@media (max-width: 899px) {
  /* her note (6 Oct): the drop's foot on the label's baseline (js/index-waves.js
     places it) — it then rose into DESIGN's N, so the label goes 8 lower and
     the drop with it */
  .hero__badge { top: calc(408 * var(--u)) !important; }   /* her next note: up again, the drop a little over the N */
}
@media (max-width: 899px) {
  /* her note (6 Oct): WEB less see-through — the same upward fade, held
     stronger at the top (was .5 / 0) */
  .display.display--hero {
    background-image: linear-gradient(-1.409deg,
      rgb(255, 255, 255) 21.325%,
      rgba(255, 255, 255, 0.75) 72.943%,
      rgba(255, 255, 255, 0.35) 95.657%);
  }
}
