/* ===========================================================
   Art By Aleen — mobile
   Design reference: Figma CDaRMBsB0pT6xI28tZI4Pz, the "iPhone 17" frames
     179:430  hero                        402x874
     206:453  landing "art i can create"  402x874
     206:468  Original Work               402x874 (a scrolling column)
     206:596  Room / size picker          402x874
     206:600  Room, chosen                402x874
     206:821  Pet portraits               402x874
     206:905  Footer                      402x617

   This file is loaded with media="(max-width:767px)" AFTER styles.css, so
   every rule here is a mobile override and none of it is wrapped in a media
   query. Desktop rules it does not touch still apply — that is deliberate:
   the interactions, entrances and state classes are the desktop ones, and the
   only things re-stated here are geometry and the two places the behaviour
   genuinely differs (Original Work scrolls instead of turning; there is no
   hover to reveal a size's price).

   ---------------------------------------------------------------
   THE UNIT

   Same convention as desktop — geometry is `calc(<figma number> * var(--u))`
   and every number is read straight off the frame — but --u is derived
   differently. Desktop letterboxes (`min(100vw/W, 100vh/H)`); a phone must
   not, so mobile scales on WIDTH alone:

       --u: calc(1cqw / 4.02)          100cqw = the section's width = 402

   From the SECTION's own width via a container query, never from 100vw.
   100vw includes the scrollbar gutter: a phone draws an overlay scrollbar and
   has none, but a narrow desktop window used to test this does, and every
   measurement would be ~10px adrift there and correct on the device. `.foot`
   already does exactly this on desktop, for the same reason.

   Sections that fill the screen take the design's own aspect and a
   `min-height:100dvh` floor, so the composition can never be clipped on a
   phone shorter than 402:874 — it simply scrolls the last few px. The stage
   keeps `inset:0; margin:auto`, so on a taller phone it centres in the section
   and the background covers the rest.
   =========================================================== */

/* --- no gutter to hold ---
   The desktop keeps `scrollbar-gutter:stable` so locking scroll cannot shift
   the composition. A phone has overlay scrollbars: there is no gutter to
   reserve and nothing shifts, so this is only here to stop a narrow DESKTOP
   window from reserving one and making --u disagree with the device. */
html{
  scrollbar-gutter:auto;
  /* a grey flash on every tap is not part of the design */
  -webkit-tap-highlight-color:transparent;
}

/* Nothing here is hoverable, so anything the desktop only shows on hover has
   to arrive some other way. Handled per case below, never with a blanket
   "pretend it is hovered". */

/* ---------- the containers --------- */
.hero,.orig,.toroom,.room,.pets{ container-type:inline-size; }
/* .foot already carries container-type on desktop */

/* A FULL-SCREEN SECTION IS EXACTLY ONE VIEWPORT TALL. Not `aspect-ratio:
   402/874`, which is what this used to say, and which is wrong on every phone
   that is not exactly 402x874 — i.e. every real one, because Chrome's address
   bar eats ~90px.

   The frames are 402x874 (0.4599). A section sized to the DESIGN height is
   874*u tall, so on a 402x780 Chrome viewport it runs 94px past the fold. The
   hero clip fills the section, so its centre sits 47px below the centre of the
   screen — and the "art i can create" line, which is centred in the clip,
   lands 44px low. Modelled across real viewports it is +29 to +47px out, and
   exactly -3px out at 402x874. That is precisely why this looked right in the
   402x874 preview iframe and wrong in Chrome.

   So: height is 100dvh, and --u fits the composition INSIDE that
   (`min(width, height)`, the desktop's own letterboxing rule) so the nav can
   never be clipped off the top on a squarer screen. The stage then centres in
   the viewport and the backgrounds, which are all object-fit:cover on the
   section rather than on the stage, still fill it edge to edge. */
.stage--hero,.stage--wide,.stage--toroom,.stage--room,.stage--pets,.stage--foot,
.orig__pin,.toroom__pin{
  --u: min(calc(1cqw / 4.02), calc(100dvh / 874));
}
/* The footer is its own board (402x617) and is scrolled to, not filled, so it
   keeps the width-only unit. */
.stage--foot{ --u: calc(1cqw / 4.02); }

.stage--hero,.stage--wide,.stage--toroom,.stage--room,.stage--pets{
  inset:0; margin:auto; width:calc(402 * var(--u));
}
.stage--hero  { height:calc(874 * var(--u)); }
.stage--room  { height:calc(874 * var(--u)); }
.stage--pets  { height:calc(874 * var(--u)); }
.stage--toroom{ height:calc(874 * var(--u)); }

/* =========================== HERO =========================== */
/* Figma 179:430. Contact moves to the LEFT of the nav and MENU to the right;
   the title drops to the middle of the screen and the tagline goes to the
   bottom. Same elements, same entrances, same transition — only placed anew.

   aspect-ratio rather than a plain 100dvh: at 402:874 the design is taller
   than some phones are, and a centred stage in a 100dvh box would push the
   nav off the top on anything squarer. This way the section grows instead and
   the page scrolls the difference. */
.hero{ height:100dvh; }

/* --- nav --- */
/* Contact, top left. Box is the union of the label (36.423,28 53.308x28.269)
   and the brush behind it (13,36.884 105x13.731). */
.nav__contact{
  left:calc(13 * var(--u)); top:calc(28 * var(--u));
  width:calc(105 * var(--u)); height:calc(28.269 * var(--u));
}
.nav__contact-brush{
  left:0; top:calc(8.884 * var(--u));
  width:calc(105 * var(--u)); height:calc(13.731 * var(--u));
}
.nav__contact-label{
  left:calc(23.423 * var(--u)); top:0;
  font-size:calc(28.605 * var(--u));
  text-shadow:calc(3.231 * var(--u)) calc(3.231 * var(--u))
              calc(6.462 * var(--u)) rgba(0,0,0,.8);
}

/* MENU, top right. The dot block sits at 31 here rather than desktop's 28, and
   the +3.3 optical nudge rides on top of it exactly as it does there — the cut
   is the same and the size is the same (35.42), so the correction is the same
   fraction of the em. See the hero note in HANDOFF.md. */
.nav__menu-label{
  left:calc(297 * var(--u)); top:calc((31 + 3.3) * var(--u));
  font-size:calc(35.42 * var(--u));
  height:calc(25 * var(--u)); line-height:calc(25 * var(--u));
}
.nav__dots{
  left:calc(351 * var(--u)); top:calc(31 * var(--u));
  width:calc(25 * var(--u)); height:calc(25 * var(--u));
}


/* ---- MENU ----
   There is no mobile frame for this one — 218:962 is the only menu the file
   has — so it is the desktop container SCALED, the same way the room's size
   groups and the pets clusters are, and anchored to the mobile nav's own dots.

   ONE factor, 0.8193, and every number below is the desktop's times it. The
   factor is set by width: the container has to hold "CUSTOM PORTRAITS" and
   still leave a margin on a 402 board, which puts it at 170 wide against the
   desktop's 207.498. Nothing here is re-composed; the proportions are the
   frame's throughout.

   Where it hangs: the desktop container's centre sits 55.75 left of the dot
   block's centre. Scaled that is 45.67, and the mobile dots are centred on
   (363.5, 43.5) — so the container's centre is 317.83 and its left is 232.83.
   Its right edge lands a hair past the board, exactly as the desktop's does. */
.menu__blob{
  left:calc(232.83 * var(--u)); top:0;
  width:calc(170 * var(--u)); height:calc(203.44 * var(--u));
  /* the dot block's centre inside this box: 130.67/170, 43.5/203.44 */
  transform-origin:76.87% 21.38%;
}
.menu__blob-art{
  left:calc(15.07 * var(--u)); top:calc(10.85 * var(--u));
  width:calc(139.87 * var(--u)); height:calc(181.74 * var(--u));
}

/* The word's open position is the desktop's offset inside the container
   (81.39, 40.15 from its top-left), scaled and re-anchored. */
.nav__menu.is-open .nav__menu-label{
  left:calc(299.51 * var(--u)); top:calc(32.89 * var(--u));
  font-size:calc(29.02 * var(--u));
}

.menu__link{ font-size:calc(23.28 * var(--u)); }
.menu__link--orig  {left:calc(316.72 * var(--u)); top:calc(66.24 * var(--u))}
.menu__link--custom{left:calc(319.99 * var(--u)); top:calc(103.10 * var(--u))}
.menu__link--pets  {left:calc(319.59 * var(--u)); top:calc(139.98 * var(--u))}

/* No hover on a phone, so there is nothing to peek with. The images are never
   given a src either — main.js only loads them on open, and this is display:none
   from the start, but the rule is here so the intent is not ambiguous. */
.menu__peeks{ display:none; }

/* The tagline is no longer in the nav row — it is the line along the bottom. */
.nav__tag{
  left:calc(106 * var(--u)); top:calc(800 * var(--u));
  width:calc(176 * var(--u));
  font-size:calc(26.19 * var(--u));
}

/* --- title --- */
/* Box is the union of the cream title (82.425,350) and the two script layers,
   which start at 50/348 — so 50/348 is the box and the children sit at offsets
   inside it, the same shape the desktop rule has. */
.hero__title{
  left:calc(50 * var(--u)); top:calc(348 * var(--u));
  width:calc(302.566 * var(--u)); height:calc(100.76 * var(--u));
}
.hero__title-main{
  left:calc(32.425 * var(--u)); top:calc(2 * var(--u));
  font-size:calc(80.416 * var(--u));
}
.hero__script-a,.hero__script-b{ font-size:calc(63.076 * var(--u)); }
.hero__script-a{ left:0;                        letter-spacing:calc(-8.8306 * var(--u)); }
.hero__script-b{ left:calc(154.044 * var(--u)); letter-spacing:calc(-3.7845 * var(--u)); }

/* ==================== ORIGINAL WORK ====================
   Figma 206:468. The reel does not turn on mobile — it travels straight up —
   but it is still a REEL ON A PINNED SCREEN, not a column you scroll. The page
   itself does not move: the wall, the title and the two leads hold still, and
   the only thing that travels is the canvases, which rise through the middle
   and fade out as they go. The wall changes under them, one per kind of work.

   It was a scrolling column at first and that was wrong: a column scrolls the
   whole section, title and all. So the desktop's structure is kept wholesale —
   a tall scroll range, a sticky pin, the stage absolutely placed on it, and
   main.js writing --rx/--ry/--rs per item from scroll position. Only the path
   those numbers describe differs: a vertical line here, an arc there. Nothing
   below re-states the pin, the stage or the copy's placement machinery; they
   are the desktop's. */
.orig{ height:420dvh; }
.orig__pin{ height:100dvh; }
/* Sharp, as the frame draws it — and the desktop's blur is a full-screen
   filter over a stack of four walls, re-rasterised every time one of them
   cross-fades. That is real work on a phone for something the design does not
   ask for. */
/* Sharp, as the frame draws it — and now that is simply which FILE the phone
   is given (main.js picks data-m, the un-blurred cut) rather than a filter
   being turned off. Nothing here has to undo a blur any more. */
.orig__bg{ transform:none; }
.stage--wide{ height:calc(874 * var(--u)); }

.orig__lead,.orig__title-main,.orig__title-script{
  text-shadow:calc(0.989 * var(--u)) calc(2.966 * var(--u))
              calc(5.932 * var(--u)) rgba(0,0,0,.8);
}
.orig__title-main{
  left:calc(59.32 * var(--u)); top:calc((103 + var(--baseline-fix)) * var(--u));
  font-size:calc(66.653 * var(--u));
}
.orig__title-script{
  left:calc(45 * var(--u)); top:calc(104.59 * var(--u));
  font-size:calc(49.389 * var(--u));
}
/* Both leads sit on one line here rather than at opposite edges of a 1980 stage. */
.orig__lead{ font-size:calc(38.593 * var(--u)); }
.orig__lead--l{ left:calc(59.84 * var(--u)); top:calc((178.43 + var(--baseline-fix)) * var(--u)); }
.orig__lead--r{ left:calc(197.1 * var(--u));  top:calc((178.43 + var(--baseline-fix)) * var(--u)); }

/* --- the reel, travelling up ---
   Every canvas is the same width and centred (the frame's 37.23 left on a 402
   board is exactly that) and keeps its own aspect through the --cw/--ch the
   desktop rules already carry — via aspect-ratio, because CSS cannot divide by
   a custom property.

   --rx/--ry are the item's CENTRE in design px, as on desktop, so the transform
   only has to pull the box back by half itself. No rotation. --rf is the fade,
   written by main.js alongside the rest. */
.reel__item{
  width:calc(326.887 * var(--u)); height:auto;
  aspect-ratio:var(--cw) / var(--ch);
  transform:
    translate(calc(var(--rx, 201) * var(--u) - 50%),
              calc(var(--ry, 455) * var(--u) - 50%))
    scale(var(--rs, 1));
  transition:none;              /* scroll is the clock; a transition only lags it */
}
/* Held out of sight until the landing has cleared, exactly as on desktop —
   then the fade is the reel's own, not a flat 1. */
.orig.is-open .reel__item{ opacity:var(--rf, 1); }
.reel__art{ position:absolute; inset:0; }

.reel__art{
  filter:drop-shadow(calc(3.471 * var(--u)) calc(5.207 * var(--u))
                     calc(3.124 * var(--u)) rgba(0,0,0,.25));
}

/* Every name is drawn to ONE box, 309.924 wide — the frame only specifies
   "landscapes", but the rule it implies is recoverable and checks out exactly.
   Each desktop item carries its own measured pair (--nw, --nfs), so nw/nfs is
   that exact string's advance per px of font size in Script; sizing each name
   to render 309.924 wide gives landscapes 59.384 against the frame's 59.392,
   i.e. 0.01% out. So the designer set every name to fill the same box, and
   these are the four sizes that do it. Without this they share one font size
   and the long ones run off the screen — "Mini Canvases" overran by ~60px. */
.reel__item--landscapes{ --nfs:59.384 }
.reel__item--abstract  { --nfs:74.545 }
.reel__item--mini      { --nfs:47.367 }
.reel__item--panels    { --nfs:106.458 }

/* Placed as a FRACTION of its own canvas rather than at a fixed offset, so it
   sits in the same place on all four however tall they are — 72.97% is where
   the frame puts "landscapes" on a 437.971-tall canvas. */
.reel__name{
  /* Centred on the canvas rather than ranged left off the frame's 8.6: the
     four names are four different widths (see --nfs), so a shared left edge
     put each one somewhere different under its own canvas. left:50% with a
     half-width pull centres all four on the same axis whatever they measure.
     The clip-path reveal still runs left to right from the name's own box. */
  left:50%; top:72.97%;
  transform:translateX(-50%);
  /* max-content rather than the frame's 309.924: the reveal clips against this
     box (`inset(0 calc(102% - draw*104%) 0 0)`), so anything the sizing above
     leaves a hair wide would be cut off at full draw rather than overflowing. */
  width:max-content; max-width:none;
  /* font-size, letter-spacing and the shadow all follow --nfs already */
}


/* ======================= PRODUCT DETAIL =======================
   Figma "iPhone 17 - 8" (211:932), 402x874. Same overlay, same states, same
   machinery as the desktop — only the geometry is re-read and ONE behaviour
   genuinely differs:

     - the canvases travel SIDEWAYS here, not up and down. The one on screen
       slides out to the left and the next arrives from the right;
     - the tilt is a press-and-drag rather than a hover, and it does not carry
       the glare (the owner's call). See main.js;
     - the CTA's brush wipes on while the CTA is HELD, since there is no hover
       to reveal it with. main.js adds .is-pressed on pointerdown.

   Nothing here re-states the overlay, the wall stack, the cross-fade or the
   reveal machinery; they are the desktop's. */
.work{ container-type:inline-size; }
.stage--work{
  --u: min(calc(1cqw / 4.02), calc(100dvh / 874));
  inset:0; margin:auto;
  width:calc(402 * var(--u)); height:calc(874 * var(--u));
}
/* The wall covers the viewport, as it does on desktop. The frame asks for
   1.5px of blur here; at this board that is under two pixels and invisible,
   and taking the sharp cut keeps the phone free of a full-screen filter and
   consistent with the reel's own wall. */
.work__bg{ transform:scale(1.03); }

.work__back{
  left:calc(24 * var(--u)); top:calc(30 * var(--u));
  gap:calc(6 * var(--u)); font-size:calc(21 * var(--u));
  text-shadow:calc(1 * var(--u)) calc(2 * var(--u)) calc(5 * var(--u)) rgba(0,0,0,.75);
}
.work__back-arrow{ width:calc(18 * var(--u)); height:calc(18 * var(--u)); }
.work__back:hover .work__back-arrow,
.work__back:focus-visible .work__back-arrow{ transform:translateX(calc(-4 * var(--u))); }
.work__back-label::after{ bottom:calc(-4 * var(--u)); height:calc(6 * var(--u)); }

/* 211:936 — the canvas box is 255x353 at 74,201. --mw/--mh are the same
   contain-fit the desktop's --bw/--bh are, worked out against this box. */
.work__deck{
  left:calc(74 * var(--u)); top:calc(201 * var(--u));
  width:calc(255 * var(--u)); height:calc(353 * var(--u));
}
/* The end-of-deck nudge goes sideways here, with the travel. */
.work__deck.is-end-next{ transform:translateX(calc(-12 * var(--u))); }
.work__deck.is-end-prev{ transform:translateX(calc(12 * var(--u))); }
.work__piece{
  width:calc(var(--mw) * var(--u)); height:calc(var(--mh) * var(--u));
  perspective:calc(700 * var(--u));
  /* SIDEWAYS. Parked a viewport away in vw for the same reason the desktop
     parks in dvh: the stage letterboxes and the window does not. */
  transform:translate(calc(-50% + var(--step, 0) * 118vw), -50%);
}
/* No glare on a touch drag — the owner's call. The tilt itself stays. */
.work__piece::after{ display:none; }

.work__title-main{
  left:calc(50 * var(--u)); top:calc((71.18 + var(--baseline-fix)) * var(--u));
  font-size:calc(83.205 * var(--u));
  text-shadow:calc(1 * var(--u)) calc(3 * var(--u)) calc(7 * var(--u)) rgba(0,0,0,.75);
}
.work__title-script{
  left:calc(34 * var(--u)); top:calc(66 * var(--u));
  font-size:calc(62.432 * var(--u));
}

/* Centred here, where the desktop ranges it left: 211:940's `left` is its
   CENTRE (the rule carries translateX(-50%)), the same way the footer's
   enquiries label is placed. */
.work__desc{
  left:calc(203.15 * var(--u)); top:calc((591 + var(--baseline-fix)) * var(--u));
  width:calc(314.299 * var(--u));
  transform:translateX(-50%);
  font-size:calc(33.75 * var(--u)); text-align:center;
  text-shadow:calc(1 * var(--u)) calc(2 * var(--u)) calc(6 * var(--u)) rgba(0,0,0,.6);
}

/* The union of the label (122.68,752) and the brush behind it
   (71,770.46 259.982x26.367), so the box starts at 71,752. */
.work__cta{
  left:calc(71 * var(--u)); top:calc(752 * var(--u));
  width:calc(259.982 * var(--u)); height:calc(70 * var(--u));
}
.work__cta-brush{
  top:calc(18.46 * var(--u));
  width:calc(259.982 * var(--u)); height:calc(26.367 * var(--u));
}
.work__cta-label{
  left:calc(51.68 * var(--u)); font-size:calc(51.981 * var(--u));
  text-shadow:calc(1 * var(--u)) calc(2 * var(--u)) calc(5 * var(--u)) rgba(0,0,0,.5);
}

.reel__open:focus-visible{ outline-width:calc(2 * var(--u)); outline-offset:calc(3 * var(--u)); }


/* ============ ORIGINAL WORK -> CUSTOM PORTRAITS ============ */
/* No mobile frame for this one, so it is the desktop transition re-proportioned
   to a 402 board: same three beats, same machinery, same classes. The wash and
   the fill are written in percentages and in --cut-y, so they need nothing
   here — only the script has to be re-sized and the section re-hung.

   The script runs 76% of the screen's width. The desktop runs it 62.8% of a
   1440 board, but mobile type here is consistently larger relative to the
   screen — the hero's script is 75% and Original Work's is 77% — and 62.8%
   reads as an afterthought on a phone. Ink width is 7.39961em for this string
   at -0.03em, so 76% of 402 is a 41.3 design px cut.

   -160dvh, matching desktop, and for the same arithmetic. Original Work is
   420dvh with a 100dvh pin, so its reel finishes 60dvh (REEL_HOLD) before the
   pin releases — at 260dvh — and Panels then holds. The wash has to start
   THERE, or those 60dvh are dead scroll: the scrollbar moves and the screen
   sits on Panels doing nothing, which is exactly what it did at -100dvh.
   420 - 160 = 260. dvh throughout so the address bar sliding away cannot
   desync the pin's range from the room's own top. */
.toroom{ height:200dvh; margin-top:-160dvh; }
.toroom__pin{
  height:100dvh;
  /* Measured the same way the desktop's +14.21 was: render the title, take the
     ink-MASS centroid of the rendered type, express it against the stage's own
     centre line. Ink runs y 391..420 at 402x874 and the mass centres on 409.03
     against a centre of 437. The plain box centre (405.5, i.e. -31.5) is the
     wrong answer here for the same reason it is on desktop — the capitals and
     the t/i ascenders are tall and sparse and drag it above the word's weight. */
  --cut-y:-27.97;
}

.toroom__title{
  left:calc(48.2 * var(--u)); top:calc(381.5 * var(--u));
  width:calc(305.6 * var(--u));
  font-size:calc(41.3 * var(--u));
  letter-spacing:-0.03em;
}


/* =========================== ROOM =========================== */
/* Figma 206:596, and 206:600 for the chosen state.

   The three size groups are the DESKTOP groups scaled — 0.45, 0.4855 and
   0.5064 — and re-hung. That is not a guess: scaling the desktop's own
   --nx/--ny/--cx/--cy/--tx/--ty/--tw by those factors reproduces Figma's mobile
   numbers to within 0.3 design px on every one of them, and the large group's
   shadow lands on 5.4/3.15/6.3, which is exactly what Figma reports for it.
   The values below are Figma's own all the same, since they are the reference.

   The one thing that is NOT part of that scale is the size labels: the
   designer re-set them larger (18.445 / 15.407 / 12.908 against a scale that
   would have given 15.66 / 15.05 / 14.18), which is why --lf and --ly are
   measured rather than derived.

   NO HOVER HERE. The desktop writes a size's price and note on when the
   pointer is over it, and at most one is visible at a time because all three
   overlap on a 1440 board. The mobile frame shows all three at once — and on
   this layout they do not overlap (the notes sit at y 252, 471 and 585) — so
   they simply arrive with the copy and a tap commits. No first-tap-to-reveal
   dance, and no pretending a touch is a hover. */
/* margin-top cancels exactly the second screen of .toroom, the way the desktop
   does: the room's top has to land where the fill finishes opening. */
.room{ height:100dvh; margin-top:-100dvh; }

.room__lead{
  left:calc(128 * var(--u)); top:calc((28 + var(--baseline-fix)) * var(--u));
  font-size:calc(46.8 * var(--u));
}
/* 206:596 says "Pick a size" and stops — the sofa line is desktop-only copy */
.room__lead-tail{ display:none; }
/* Two lines and centred here, not one nowrap line across a 1440 board. */
.room__sub{
  left:calc(73 * var(--u)); top:calc((77 + var(--baseline-fix)) * var(--u));
  width:calc(255 * var(--u));
  font-size:calc(22.219 * var(--u));
  white-space:normal; text-align:center;
}

/* THE SCENE SPANS THE VIEWPORT, NOT THE STAGE. --u fits the composition
   inside the screen (`min(width, height)`), so on a phone squarer than 402:874
   the stage is narrower than the viewport and centred — on a 440x860 Pro Max
   with the address bar showing that is 22px of bare wall down each side. The
   copy and the canvases are happy with that; the furniture is not, because the
   dresser and the plant are cut off by the frame edge in the design and have
   to keep meeting the real edge. Same reasoning as the desktop rule, which
   sizes this off 100vw for the same reason.

   100cqw, not 100vw: the container is .room, so this is the section's own
   width and no scrollbar can shift it. */
.room__scene{
  left:50%; translate:-50% 0;
  width:100cqw; top:calc(546 * var(--u)); height:calc(328 * var(--u));
}

/* All three are written on with the copy — see the note above about hover. */
.room.is-copy-in .size__note,
.room.is-copy-in .size__num,
.room.is-copy-in .size__cur{--draw:1;opacity:1}

/* Selected. The frame grows the chosen canvas as well as moving it, and moves
   it on both axes — the desktop only slides it sideways because its three sizes
   already share a centre line. --selscale is a new knob rather than the
   existing --sts, which belongs to the unused .is-stacking state. */
.room.is-art-in .size.is-selected{
  transform:translate(calc(var(--selx) * var(--u)), calc(var(--sely, 0) * var(--u)))
            scale(var(--selscale, 1)) rotate(var(--rot, 0deg));
}

.size--l{
  --bx:35.4500; --by:157.0000; --bw:216.0000; --bh:216.0000;
  --sx:5.400; --sy:3.150; --sb:6.300;
  --ly:201.000; --lf:18.445;
  --nx:119.700; --ny:134.550; --nf:53.861;
  --cx:185.691; --cy:149.613; --cf:37.364;
  --tx:-18.450; --ty:94.950; --tw:253.350; --tf:23.441;
  --selx:57.1631; --sely:132.0546; --selscale:1.222727;
}
.size--m{
  --bx:239.4233; --by:387.0000; --bw:124.7632; --bh:181.6405;
  --sx:4.855; --sy:4.369; --sb:1.942;
  --ly:165.577; --lf:15.407;
  --nx:79.242; --ny:106.339; --nf:48.938;
  --cx:115.230; --cy:119.833; --cf:33.948;
  --tx:-19.423; --ty:84.003; --tw:163.150; --tf:17.035;
  --selx:-101.1918; --sely:-80.7657; --selscale:1.454021;
}
.size--s{
  --bx:87.8247; --by:531.1214; --bw:83.2791; --bh:117.2948;
  --rot:-0.08deg;
  --sx:3.038; --sy:4.051; --sb:2.025;
  --ly:113.071; --lf:12.908;
  --nx:42.953; --ny:64.560; --nf:39.596;
  --cx:72.004; --cy:75.455; --cf:27.468;
  --tx:-30.825; --ty:53.949; --tw:144.522; --tf:15.743;
  --selx:71.1489; --sely:-192.7142; --selscale:2.251670;
}

/* --- the chosen screen (206:600) --- */
.room__done-title{
  left:calc(29 * var(--u)); top:calc((156 + var(--baseline-fix)) * var(--u));
  font-size:calc(74.171 * var(--u));
}
.room__done-sub{
  left:calc(107 * var(--u)); top:calc((584 + var(--baseline-fix)) * var(--u));
  width:calc(212 * var(--u));
  font-size:calc(28.897 * var(--u));
  white-space:normal;
}
.room__wa{
  left:calc(255 * var(--u)); top:calc(584 * var(--u));
  width:calc(65.939 * var(--u)); height:calc(65.939 * var(--u));
}

/* ======================= PET PORTRAITS =======================
   Figma 206:821. Same section, same choreography — the slices deal out unlit,
   the lamp swings onto them, the light strikes, the copy follows and "More
   than one pet?" comes last. None of that is restated here; only geometry is.

   Two clusters turn out to be the desktop's, scaled and re-hung, which is how
   the numbers below were checked rather than guessed:

     the five slices   x0.30287  (main 374.453 -> 113.413, and every --sts
                                  lands back on the desktop's own value)
     the hanging blank x0.55790  (wood 349.244 -> 194.843; the price, the CTA
                                  and "Nothing's charged yet." all land on
                                  Figma's mobile numbers to 0.02)

   The copy block is NOT a scale — it was re-set for the narrow board and every
   size here is Figma's own. */
.pets{ height:100dvh; }

/* --- the lamp ---
   Re-lifted from THIS frame the same way the desktop pair was: export the
   frame as SVG, strip the embedded rasters (13.9 MB -> 311 KB), and the vector
   paths are left in frame coordinates with identity transforms. The mobile
   lamp is posed differently — it hangs on the right and points up and left,
   where the desktop one points down — so the desktop files cannot be reused.

   Split on the same principle: the plate is screwed to the wall and must not
   swing, so lamp-mount-m.svg is the three tall narrow paths at x 362..373 and
   lamp-head-m.svg is the other seventeen. Both carry viewBox "279 336 94 124"
   and sit on the same box, so they overlay exactly. The head pivots on the
   joint where the arm meets the plate, ~(363, 407) = 89.4% / 57.3%. */
.pets__lamp-mount,.pets__lamp-head{
  left:calc(279 * var(--u)); top:calc(336 * var(--u));
  width:calc(94 * var(--u)); height:calc(124 * var(--u));
}
.pets__lamp-head{ transform-origin:89.4% 57.3%; }

/* Drawn well past its box by the blur, exactly as the desktop beam is: the box
   is the union of the three Gaussian filter regions the frame reports. */
.pets__beam{
  left:calc(-33.18 * var(--u)); top:calc(-24.67 * var(--u));
  width:calc(440.26 * var(--u)); height:calc(431.91 * var(--u));
}

/* --- the slices --- */
.slice{
  filter:drop-shadow(calc(-4.543 * var(--u)) calc(-2.726 * var(--u))
                     calc(1.212 * var(--u)) rgba(0,0,0,.25))
         saturate(calc(.45 + .55 * var(--lit))) brightness(var(--lit));
}
.slice--main{--sx:151.069; --sy:44;  --sw:113.413;--sh:151.893;--stx:0;      --sty:0;       --sts:1}
.slice--l1  {--sx:181;     --sy:176; --sw:59.965; --sh:106.604;--stx:-3.207; --sty:-109.356;--sts:1.42482}
.slice--r1  {--sx:260;     --sy:204; --sw:62.019; --sh:110.257;--stx:-83.234;--sty:-139.182;--sts:1.37763}
.slice--l2  {--sx:106;     --sy:128; --sw:54.491; --sh:96.873; --stx:74.530; --sty:-56.490; --sts:1.56793}
.slice--r2  {--sx:282;     --sy:120; --sw:53.738; --sh:95.533; --stx:-101.093;--sty:-47.820;--sts:1.58995}

/* --- title and copy --- */
.pets__eyebrow{
  left:calc(38 * var(--u)); top:calc((47 + var(--baseline-fix)) * var(--u));
  font-size:calc(35.017 * var(--u));
}
.pets__eyebrow-script{
  left:calc(71.267 * var(--u)); top:calc(63.194 * var(--u));
  font-size:calc(21.799 * var(--u)); letter-spacing:-0.03em;
  text-shadow:calc(-2.189 * var(--u)) 0 calc(2.189 * var(--u)) rgba(0,0,0,.5);
}
/* Two lines here, not one. The -0.65 is the desktop's -1.5 nudge for this
   condensed italic carried across as the same fraction of the em (0.0407). */
.pets__more{
  left:calc(262 * var(--u)); top:calc((73 - 0.65) * var(--u));
  width:calc(81 * var(--u));
  font-size:calc(15.881 * var(--u));
  white-space:normal;
}
.pets__title{
  left:calc(25 * var(--u)); top:calc((383 + var(--baseline-fix)) * var(--u));
  width:calc(171 * var(--u));
  font-size:calc(23.267 * var(--u));
  white-space:normal;
}
.pets__nope{
  left:calc(84 * var(--u)); top:calc(418 * var(--u));
  font-size:calc(13.96 * var(--u)); letter-spacing:-0.03em;
}
/* z-index:1 — .pets__brush is an absolutely positioned box that comes LATER in
   the markup, so it paints over anything earlier that its box overlaps. On the
   desktop board nothing does; here the stroke's box starts at 754 and this
   line runs to ~757, and the descenders of "strung and ready" were being cut
   off by it. The stroke's own ink starts at 797, so nothing actually collides
   — and the asset is matted onto --work-bg rather than transparent (see the
   download_assets note in Gotchas), so its box is opaque even where it looks
   like bare wall. */
.pets__sub{
  left:calc(30 * var(--u)); font-size:calc(23.265 * var(--u));
  white-space:normal; z-index:1;
}
.pets__sub--1{ top:calc((688.19 + var(--baseline-fix)) * var(--u)); width:calc(329 * var(--u)); }
.pets__sub--2{ top:calc((739.59 + var(--baseline-fix)) * var(--u)); width:calc(313.123 * var(--u)); }

/* --- the hanging blank --- */
.hang{
  left:calc(81.99 * var(--u)); top:calc(369 * var(--u));
  width:calc(286.35 * var(--u)); height:calc(267.75 * var(--u));
}
.hang__wood{
  left:calc(40.36 * var(--u)); top:0;
  width:calc(194.843 * var(--u)); height:calc(346.387 * var(--u));
}
.hang__num{
  left:calc(108.23 * var(--u)); top:calc(167.37 * var(--u));
  font-size:calc(39.169 * var(--u)); letter-spacing:-0.03em;
}
.hang__cur{
  left:calc(145.05 * var(--u)); top:calc(178.53 * var(--u));
  font-size:calc(28.568 * var(--u));
}
.hang__cta{
  left:0; top:calc(213.12 * var(--u));
  font-size:calc(39.169 * var(--u)); letter-spacing:-0.03em;
}
.hang__note{
  left:calc(201.41 * var(--u)); top:calc((256.63 + var(--baseline-fix)) * var(--u));
  font-size:calc(12.67 * var(--u));
}

/* --- the memo ---
   Its own asset (data-m in the markup), and placed on the MASK GROUP's box
   (206:823, 15/754 391x123.82) rather than on the raw image's.

   The frame masks a 525.539x39.885 image with an ellipse, and neither half of
   that survives on its own: the desktop stroke squashed into a 40-tall box
   collapsed to a 13px sliver of ink spilling off both screen edges, which is
   the "doesn't appear fully" glitch. The mask group exported flat is the
   stroke as the frame actually draws it — rounded left end, ragged right,
   nothing to re-mask — so it goes in at the group's own box. */
.pets__brush{
  left:calc(15 * var(--u)); top:calc(754 * var(--u));
  width:calc(391 * var(--u)); height:calc(123.82 * var(--u));
}
.pets__memo{
  left:calc(35.853 * var(--u)); top:calc((798.965 + var(--baseline-fix)) * var(--u));
  width:calc(301.528 * var(--u));
  font-size:calc(16.235 * var(--u));
}

/* ========================== FOOTER ==========================
   Figma 206:905, a 402x617 board — the only frame that is not 874 tall, the
   same way the desktop footer is the only one that is not 1080.

   Every element is re-placed, but every SIZE is the desktop's at x0.5271: the
   three social icons land on 64.835 / 58.510 / 55.347 against 123 / 111 / 105,
   and the enquiries stroke on 269.017 x 33.172 against 514 x 63.38. That is
   also what identifies the two unnamed icon layers — `image 16` is TikTok and
   `image 15` is Facebook, by size alone.

   The nav lefts are CENTRES, as they are on desktop; the frame's own boxes
   give 40.74 / 108.71 / 192.01 / 268.68, and the rendered ink in Figma's own
   export centres on 39.5 / 108.5 / 191.5 / 268. */
.foot{ aspect-ratio:402 / 617; }

/* Its own portrait crop (data-m in the markup) — the landscape photo stretched
   into a 401x719 box turns the easels into stilts. */
.foot__bg{
  left:calc(1 * var(--u)); top:calc(-15 * var(--u));
  width:calc(401 * var(--u)); height:calc(719 * var(--u));
  object-fit:cover;
}

/* --- nav --- */
.foot__nav-link{
  top:calc((45 + var(--baseline-fix)) * var(--u));
  font-size:calc(12.1 * var(--u));
}
.foot__nav-link--home  { left:calc(40.74 * var(--u)); }
.foot__nav-link--custom{ left:calc(108.71 * var(--u)); }
.foot__nav-link--orig  { left:calc(192.01 * var(--u)); }
.foot__nav-link--pets  { left:calc(268.68 * var(--u)); }
.foot__nav-link::after{ bottom:calc(-3 * var(--u)); height:calc(1 * var(--u)); }

/* Two lines here, set tight (Figma runs them at 0.857). The break is a <br> in
   the markup rather than a narrow box: "Art By Aleen" at 110.387 measures 343
   wide against a 350.7 box, so it would not have wrapped on its own. */
.foot__wordmark{
  left:calc(31 * var(--u)); top:calc((77 + var(--baseline-fix)) * var(--u));
  width:calc(350.698 * var(--u));
  font-size:calc(110.387 * var(--u)); line-height:0.857;
}
.br-m{ display:inline; }

.foot__where{
  left:calc(31 * var(--u)); top:calc((280 + var(--baseline-fix)) * var(--u));
  font-size:calc(20.777 * var(--u));
}

/* --- social --- */
.foot__social-link--ig{ left:calc(303 * var(--u)); top:calc(148 * var(--u)); width:calc(64.835 * var(--u)); height:calc(64.835 * var(--u)); }
.foot__social-link--tt{ left:calc(244 * var(--u)); top:calc(213 * var(--u)); width:calc(58.510 * var(--u)); height:calc(58.510 * var(--u)); }
.foot__social-link--fb{ left:calc(313 * var(--u)); top:calc(267 * var(--u)); width:calc(55.347 * var(--u)); height:calc(55.347 * var(--u)); }

/* --- enquiries ---
   Sized to the stroke's own box, as on desktop — an inset:0 box over the whole
   stage would mean touching anywhere in the footer wipes it on.

   The label and the pill are CENTRED in that box rather than left at the
   frame's own offsets, which have the pair ~7px left of centre and each a few
   px out vertically (the label at 7.888 from the top of a 33.172 box whose
   line is 23.9 tall, the pill at 5.259 where centred is 6.675).

   Centred by arithmetic, not by flex. Flex distributed the free space wrongly
   here — it put 17px before the label and 51px in the gap where the gap was
   set to 11.8 — and the totals were right, so it was not worth chasing. The
   widths are known and fixed: the label renders 79.24 and the pill is 65.06,
   with the frame's own 11.83 between them, so the pair is 156.13 in a 269.017
   box and starts at (269.017 - 156.13) / 2 = 56.44.

   z-index:1 on both: the stroke behind them is absolutely positioned, so a
   static child paints UNDERNEATH it — which swallowed the pill entirely and
   washed the label out. */
.foot__enquiries{
  left:calc(66 * var(--u)); top:calc(540 * var(--u));
  width:calc(269.017 * var(--u)); height:calc(33.172 * var(--u));
}
/* The stroke is not hover-revealed here — there is nothing to hover with, and
   the frame draws it. Same call as the room's prices: where the desktop hides
   something behind :hover and the mobile frame shows it, it is simply on. */
.foot__enq-brush{ --draw:1; }
/* .foot__enq-label's `left` is its CENTRE — the desktop rule carries
   translateX(-50%) — so this is 56.44 + 79.24/2, not 56.44. Feeding it the
   frame's own box-left was the real reason the pair sat left of centre: it was
   being read as a centre and losing another half-width on top. */
.foot__enq-label{
  z-index:1;
  left:calc(96.06 * var(--u));
  top:calc(50% - 9.65 * var(--u));            /* line-height 1 at 19.295 */
  font-size:calc(19.295 * var(--u)); line-height:1;
}
.foot__contact{
  z-index:1;
  left:calc(147.51 * var(--u));               /* 56.44 + 79.24 + 11.83 */
  top:calc(50% - 9.911 * var(--u));           /* half of 19.822 */
  width:calc(65.058 * var(--u)); height:calc(19.822 * var(--u));
  border-radius:calc(25.41 * var(--u));
  font-size:calc(18.261 * var(--u));
  padding-bottom:calc(1.57 * var(--u));
}

/* --- legal ---
   Both lines share y here rather than stacking: the frame runs them across the
   bottom edge, the copyright at 8 and the rest at 127. */
/* --1 is the hand-painted line and --2 is the copyright — not the other way
   round, which is what put them on top of each other the first time. */
/* The frame sets these side by side on one line (--2 at 8, --1 at 127, both
   at 596.46) and the owner asked for them stacked, centred and smaller. Both
   are centred on the board's own middle now, --1 (the hand-painted line) over
   --2 (the copyright), which is the order the desktop footer already uses. */
.foot__legal{
  font-size:calc(11 * var(--u));
  left:50%; transform:translateX(-50%);
}
.foot__legal--1{ top:calc((580 + var(--baseline-fix)) * var(--u)); }
.foot__legal--2{ top:calc((596.46 + var(--baseline-fix)) * var(--u)); }
