/* ===========================================================================
   mobile.css — shared responsive corrections for latteceramiche.com

   Loaded on every page AFTER that page's own <style> block, so where both
   declare !important on the same property, the rule here wins the tie.

   WHY THIS FILE EXISTS
   Each page carries its own hand-written mobile block whose rules match on the
   *text of the inline style attribute*, e.g.

       [style*="grid-template-columns: 1fr 1fr"] { grid-template-columns: 1fr; }

   That only fires when the markup happens to use a value someone remembered to
   add to that page's list. privacy.html lays its rows out with
   "90px 340px 1fr" while its stylesheet only listed "90px 1fr" and
   "110px 1fr", so a 474px-wide grid stayed three columns on a 375px phone:
   headings ran off-screen and the body text collapsed into a 15px strip.

   The rules below key off structure instead of exact strings, so a new value
   in the markup cannot slip past them.
   =========================================================================== */


/* ---------------------------------------------------------------------------
   1. GRIDS — collapse by structure, not by string match
   --------------------------------------------------------------------------- */

@media (max-width: 1099px) {

  /* Every inline grid collapses, whatever its column value. This supersedes
     the enumerated lists in the per-page blocks and closes the gap that broke
     privacy.html. Print layouts (mm columns) are left alone. */
  [style*="grid-template-columns"] {
    grid-template-columns: 1fr !important;
  }

  /* Exception: the design library reads better two-up, even on a phone. */
  [data-screen-label="Designs"] > [style*="grid-template-columns"] {
    grid-template-columns: 1fr 1fr !important;
    gap: 10px !important;
  }

  /* A collapsed grid no longer needs a desktop-sized column gap. */
  [style*="grid-template-columns"][style*="gap: 44px"],
  [style*="grid-template-columns"][style*="gap: 48px"],
  [style*="grid-template-columns"][style*="gap: 56px"],
  [style*="grid-template-columns"][style*="gap: 64px"],
  [style*="grid-template-columns"][style*="gap: 72px"],
  [style*="grid-template-columns"][style*="gap: 80px"],
  [style*="grid-template-columns"][style*="gap: 96px"] {
    gap: 20px !important;
  }
}

/* ---------------------------------------------------------------------------
   1b. STICKY COLUMN HEADINGS
   index, about and contact each pin a heading beside a scrolling column of
   text ("position: sticky; top: 130px"). That reads well in two columns; once
   the grid collapses to one, the heading detaches and floats over the body
   copy it was meant to sit next to — "MORE THAN TILES. LASTING IMPRESSIONS."
   was printing straight through the paragraph beneath it.

   Scoped to top:130px so the deliberate scroll scenes are untouched: the
   full-height sticky panels in about.html and carvotech.html, and the
   stacking cards at top:120px in index.html.
   --------------------------------------------------------------------------- */

@media (max-width: 1099px) {
  [style*="position: sticky"][style*="top: 130px"] {
    position: static !important;
  }

  /* and structurally, for anything added later: a sticky child of a grid that
     has just been collapsed to one column has nothing left to sit beside. */
  [style*="grid-template-columns"] > [style*="position: sticky"][style*="top: 1"] {
    position: static !important;
  }
}


@media (max-width: 620px) {
  /* one across on a phone */
  [data-screen-label="Designs"] > [style*="grid-template-columns"] {
    grid-template-columns: 1fr !important;
    gap: 14px !important;
  }
}


/* ---------------------------------------------------------------------------
   2. THE WORD-REVEAL CLIP BOX
   fx.js wraps each word of a [data-words] headline in an inline-block with
   overflow:hidden so the word can slide up into view. When the word is wider
   than the space left on the line it wraps *inside its own clip box* and the
   second line is cut off — about.html was showing 41px of an 89px headline.
   Keeping each clip box on a single line lets the words wrap between each
   other as normal text does. fx.js sets this too; this is the safety net for
   any headline rendered before the script runs.
   --------------------------------------------------------------------------- */

/* !important, and deliberately more specific than the per-page rule
       [style*="white-space: nowrap"] { white-space: normal !important; }
   which the pages use as an overflow guard. That guard now matches the very
   inline style fx.js writes here, and would otherwise undo this fix. */
[data-words] > span,
[data-words] span > span {
  white-space: nowrap !important;
  max-width: 100%;
}

/* Reveal masks written as inline styles clip their own descenders when the
   line-height is tighter than the glyph ink box (a 22px/1.15 heading needs
   28px but is given a 25px box). A little bottom padding, pulled back out
   with a negative margin, gives the ink room without moving the baseline. */
/* Not inside a media query: the footer wordmark clips its own descenders at
   every width, and the negative margin cancels the added padding so nothing
   moves. */
span[style*="display: block"][style*="overflow: hidden"],
[style*="overflow: hidden"][style*="line-height: 1;"] {
  padding-bottom: 0.26em !important;
  margin-bottom: -0.26em !important;
}

/* The slide captions on the home carousel are a flex row of
   number / name / room-and-size. The per-page rules make flex rows wrap on
   mobile, so the row becomes two or three lines inside a mask that was sized
   for one — the name was being cut in half. Giving the mask a right edge lets
   it size to the wrapped content instead. */
@media (max-width: 620px) {
  /* The slide has three overlays — the "OUR TILES — 02 / 06" chip top-left,
     the caption, and the prev/next arrows — competing for a 300px-tall photo
     of a tile, which is the one thing the section exists to show.

     On a phone they are separated by axis rather than stacked: chip stays top
     left, arrows move to top right, and the caption becomes a slim bar along
     the bottom edge. Nothing lands in the middle of the tile. */
  [style*="bottom: 26px"][style*="overflow: hidden"] {
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;

    /* A fixed height, identical on every slide. The carousel keeps the
       outgoing slide at opacity 1 and orders slides by z-index instead, so
       all six caption bars are painted on top of each other. While their
       heights varied with the text ("FEATURE WALL · 600×1200" wraps where
       "BEDROOM · 600×1200" does not) the taller ones poked out above the
       active bar as a stray white block over the photo. */
    height: 62px !important;
  }
  [style*="bottom: 26px"][style*="overflow: hidden"] > [style*="display: flex"] {
    gap: 0 10px !important;
    padding: 0 16px !important;
    height: 100% !important;
    box-sizing: border-box !important;
    align-content: center !important;
    align-items: center !important;
    background: #FFFFFF !important;
  }

  /* No wipe on a phone.

     Each slide is revealed by a clip-path wipe on its wrapper. clip-path
     clips every descendant, so the caption is sliced in half along with the
     photo while the wipe runs — mid-transition the bar reads "OOM · 600x1200"
     because the left of it has been clipped away. A child cannot opt out of
     an ancestor's clip-path, so the wipe comes off on small screens and the
     slides cross-fade instead. The photo keeps its ken-burns drift. */
  [data-mask-reveal] > div[style*="overflow: hidden"] {
    animation: none !important;
    clip-path: none !important;
  }

  /* Only the active slide's caption may paint.

     The carousel layers slides by z-index and keeps the outgoing one at
     opacity 1: z-index 3 is the incoming slide (revealed by a wipeIn
     clip-path), z-index 2 is the outgoing slide, and the rest sit at
     z-index 1 / opacity 0. The wipe uncovers the new caption left-to-right
     while the old one is still fully painted underneath, so two different
     captions were legible at once — harmless when each was a small box, very
     visible now they are full-width bars. The framework rewrites these
     inline z-index values as slides advance, so the selector follows along. */
  [style*="overflow: hidden"]:not([style*="z-index: 3"]) > [style*="bottom: 26px"] {
    opacity: 0 !important;
  }

  /* The six-segment progress bar comes off on phones. It sits across the
     bottom edge where the caption now lives, and the prev/next arrows plus
     the "OUR TILES — 02 / 06" counter already say where you are and how to
     move. Left in place on desktop. */
  [data-mask-reveal] > [style*="bottom: 0px"][style*="display: flex"],
  [data-mask-reveal] > [style*="bottom: 0"][style*="display: flex"] {
    display: none !important;
  }

  /* arrows out of the caption's way, opposite the counter chip */
  [style*="bottom: 22px"][style*="right: 24px"][style*="z-index: 4"] {
    top: 14px !important;
    bottom: auto !important;
    right: 14px !important;
  }
}


/* ---------------------------------------------------------------------------
   3. THE HERO
   index.html builds "surfaces / that last" as an inline-flex row. Flex items
   shrink below their content width, so at 375px the words broke mid-letter —
   "LATTE SURFAC / ES  THAT LA / ST" — and the glyphs of "Latte" collided with
   those of "surfaces" by 17px. Letting the row wrap puts each phrase on its
   own line instead.
   --------------------------------------------------------------------------- */

@media (max-width: 1099px) {
  h1 [style*="display: inline-flex"] {
    display: block !important;
  }
  h1 [style*="display: inline-flex"] > span {
    display: block !important;
  }
}


/* ---------------------------------------------------------------------------
   3b. THE HERO IS A FIXED-HEIGHT FLEX COLUMN
   index.html's hero is "min-height: 100vh; display: flex; flex-direction:
   column" holding a tile carousel with "flex: 1; min-height: 440px".

   flex-basis is 0, so the carousel contributes nothing when the header's
   height is worked out; the header settles at exactly 100vh (812px) and the
   carousel's own min-height then makes it overflow rather than grow its
   parent. Measured on a 375x812 screen: header 0-812, carousel 686-986, and
   the next section starting at 902 — inside the carousel — painting its
   opaque background over the bottom 84px of the image. That is the clipped
   tile shot and the band of dead white space below it.

   On a phone the hero's content is taller than the viewport anyway, so the
   100vh floor has nothing to do; dropping it lets the column size to content.
   --------------------------------------------------------------------------- */

@media (max-width: 1099px) {
  [style*="min-height: 100vh"][style*="display: flex"] {
    min-height: 0 !important;
  }
  [style*="flex: 1"][style*="min-height: 440px"] {
    flex: 0 0 auto !important;
    min-height: 300px !important;
  }
}


/* ---------------------------------------------------------------------------
   4. VERTICAL RHYTHM
   The section paddings are tuned for a 1100px canvas. The per-page blocks
   already pull the left/right gutters in to 20px; these bring the top/bottom
   back to a phone-sized scale. Values are the desktop ones at ~0.58, floored
   at 40px. Longest match wins, so "padding: 150px 46px 130px" overrides the
   shorter "padding: 150px" rule above it.
   --------------------------------------------------------------------------- */

@media (max-width: 1099px) {
  [style*="padding: 100px 48px"] { padding-top: 56px !important; padding-bottom: 56px !important; }
  [style*="padding: 100px 48px 110px"] { padding-top: 56px !important; padding-bottom: 64px !important; }
  [style*="padding: 100px 48px 130px"] { padding-top: 56px !important; padding-bottom: 76px !important; }
  [style*="padding: 110px 48px"] { padding-top: 64px !important; padding-bottom: 64px !important; }
  [style*="padding: 110px 48px 30px"] { padding-top: 64px !important; padding-bottom: 40px !important; }
  [style*="padding: 120px 48px"] { padding-top: 68px !important; padding-bottom: 68px !important; }
  [style*="padding: 120px 48px 110px"] { padding-top: 68px !important; padding-bottom: 64px !important; }
  [style*="padding: 130px 48px"] { padding-top: 76px !important; padding-bottom: 76px !important; }
  [style*="padding: 130px 48px 110px"] { padding-top: 76px !important; padding-bottom: 64px !important; }
  [style*="padding: 130px 48px 120px"] { padding-top: 76px !important; padding-bottom: 68px !important; }
  [style*="padding: 130px 48px 130px"] { padding-top: 76px !important; padding-bottom: 76px !important; }
  [style*="padding: 140px 46px 130px"] { padding-top: 80px !important; padding-bottom: 76px !important; }
  [style*="padding: 140px 48px"] { padding-top: 80px !important; padding-bottom: 80px !important; }
  [style*="padding: 140px 48px 120px"] { padding-top: 80px !important; padding-bottom: 68px !important; }
  [style*="padding: 150px"] { padding-top: 88px !important; padding-bottom: 88px !important; }
  [style*="padding: 150px 46px 130px"] { padding-top: 88px !important; padding-bottom: 76px !important; }
  [style*="padding: 150px 46px 140px"] { padding-top: 88px !important; padding-bottom: 80px !important; }
  [style*="padding: 150px 48px 0"] { padding-top: 88px !important; padding-bottom: 0 !important; }
  [style*="padding: 150px 48px 80px"] { padding-top: 88px !important; padding-bottom: 48px !important; }
  [style*="padding: 150px 48px 90px"] { padding-top: 88px !important; padding-bottom: 52px !important; }
  [style*="padding: 170px 48px 60px"] { padding-top: 100px !important; padding-bottom: 40px !important; }
  [style*="padding: 190px 48px 60px"] { padding-top: 112px !important; padding-bottom: 40px !important; }
  [style*="padding: 190px 48px 70px"] { padding-top: 112px !important; padding-bottom: 40px !important; }
  [style*="padding: 190px 48px 90px"] { padding-top: 112px !important; padding-bottom: 52px !important; }
  [style*="padding: 60px 48px 40px"]  { padding-top: 40px !important; padding-bottom: 40px !important; }
  [style*="padding: 60px 48px 90px"]  { padding-top: 40px !important; padding-bottom: 52px !important; }
  [style*="padding: 64px 48px 32px"]  { padding-top: 40px !important; padding-bottom: 40px !important; }
  [style*="padding: 76px 96px"]       { padding-top: 44px !important; padding-bottom: 44px !important; }
  [style*="padding: 80px 48px 40px"]  { padding-top: 48px !important; padding-bottom: 40px !important; }
  [style*="padding: 90px 20px"]       { padding-top: 52px !important; padding-bottom: 52px !important; }
  [style*="padding: 90px 48px 40px"]  { padding-top: 52px !important; padding-bottom: 40px !important; }
}

/* Card padding. The contact enquiry card kept its 56px desktop inset on a
   375px screen, which left the form inputs 229px wide — a third of the
   viewport spent on padding. */
@media (max-width: 620px) {
  [style*="padding: 56px"]          { padding: 22px !important; }
  [style*="padding: 34px"]          { padding: 18px !important; }
  [style*="padding: 36px 32px"]     { padding: 20px 16px !important; }
  [style*="padding: 36px 26px 30px"]{ padding: 20px 16px !important; }
  [style*="padding: 40px 28px 34px"]{ padding: 22px 16px !important; }
  [style*="padding: 40px 28px"]     { padding: 22px 16px !important; }
  [style*="padding: 40px 48px 32px"]{ padding: 22px 16px !important; }
}


/* ---------------------------------------------------------------------------
   4b. THE FINISH COMPARISON SLIDER (products.html)
   The caption strip — the sentence about the finish plus the live "63% DUNE"
   readout — was absolutely positioned along the bottom of the slider. At full
   size that overlay works; the panel is small against a 560px image.

   Narrower, it stops working. The slider is cut to 320px, the sentence wraps
   to three lines, and the panel ends up covering the middle of the tile
   photograph — the one thing the section exists to show. The panel is 94%
   opaque, so the picture reads through the text, and the "DRAG" pill sits
   behind it too.

   The strip is now a sibling of the slider inside a position:relative wrapper
   rather than a child of it, so it can simply sit below the picture here and
   still be lifted back over it on desktop. Backgrounds come off — below the
   image the text is on the page, so the panels are no longer doing anything.

   The "DRAG" pill keeps its designed spot just under the handle. It only had
   to move while the caption was overlaid there; with the caption gone from
   the picture it has the lower half of the frame to itself again.
   --------------------------------------------------------------------------- */

@media (max-width: 1099px) {
  [style*="bottom: 22px"][style*="left: 24px"][style*="right: 24px"][style*="justify-content: space-between"] {
    position: static !important;
    margin-top: 16px;
    align-items: baseline !important;
    gap: 16px !important;
  }
  [style*="bottom: 22px"][style*="left: 24px"][style*="right: 24px"][style*="justify-content: space-between"] > p {
    background: none !important;
    padding: 0 !important;
    font-size: 14px !important;
    line-height: 1.55 !important;
    max-width: none !important;
  }
  [style*="bottom: 22px"][style*="left: 24px"][style*="right: 24px"][style*="justify-content: space-between"] > span {
    background: none !important;
    padding: 0 !important;
    flex: 0 0 auto !important;
    white-space: nowrap !important;
  }
}


/* ---------------------------------------------------------------------------
   4c. THE CARVOTECH NAV
   carvotech.html has its own fixed nav: a brand row ("<- Latte Ceramiche" plus
   the CarvoTech wordmark) on the left, desktop links in the middle, and the
   hamburger on the right. On a 375px screen the brand row alone measures 332
   of the 335px available, so the hamburger wraps to a second line and the bar
   grows to 158px tall, dropping the button on top of the hero image.

   Tightening the brand row puts the whole bar back on one line. The back-link
   is exempted from the 12px type floor below — at 11px with normal tracking
   it is still a legible nav label, and the extra width is what breaks the row.
   --------------------------------------------------------------------------- */

/* Every nav on the site carries data-nav="1"; carvotech's is distinguished by
   its z-index of 90, where the shared header uses 100. */
@media (max-width: 620px) {
  nav[style*="z-index: 90"] {
    flex-wrap: nowrap !important;
    gap: 12px !important;
    padding-left: 16px !important;
    padding-right: 16px !important;
  }
  nav[style*="z-index: 90"] > div:first-of-type {
    gap: 12px !important;
    min-width: 0 !important;
    flex: 0 1 auto !important;
  }
  nav[style*="z-index: 90"] > div:first-of-type > a:first-child {
    font-size: 11px !important;
    letter-spacing: 0.08em !important;
  }
  nav[style*="z-index: 90"] > div:first-of-type > a:last-child {
    font-size: 15px !important;
  }
}


/* ---------------------------------------------------------------------------
   4d. CARVOTECH CHAPTER HEADERS
   Each of the six chapters labels its scene with two absolutely positioned
   clusters: "CHAPTER 05 —— 600 x 1200 MM" pinned left, and the "05 / 06"
   counter pinned right. At 1100px they sit far apart. At 375px the left
   cluster runs to x=324 while the counter starts at x=261, so the size and
   the counter print straight through each other.

   Dropping the connector rule and easing the very wide 0.26em tracking pulls
   the left cluster back inside its half of the row.
   --------------------------------------------------------------------------- */

@media (max-width: 620px) {
  [style*="top: 104px"][style*="left: 46px"] {
    gap: 10px !important;
    left: 16px !important;
  }
  /* the 44px hairline between the two labels */
  [style*="top: 104px"][style*="left: 46px"] > [style*="width: 44px"] {
    display: none !important;
  }
  [style*="top: 104px"][style*="left: 46px"] > span,
  [style*="top: 104px"][style*="right: 46px"] {
    letter-spacing: 0.08em !important;
  }
  [style*="top: 104px"][style*="right: 46px"] {
    right: 16px !important;
  }
}


/* ---------------------------------------------------------------------------
   4e. THE CARVOTECH FINISH PICKER
   A fixed pill at bottom centre listing the six finishes. On desktop it is one
   row about 40px tall. On a phone the page's own guard makes flex rows wrap,
   so it becomes three rows 128px tall and, being fixed, it parks that block
   over whatever is at the bottom of the viewport — mid-transition it lands on
   the chapter header and hides the tile size.

   A single row does not fit either: the six labels plus their padding measure
   467px against 375px of screen, so MIDNIGHT was sliced and GRIS fell off the
   end entirely. Closing that 92px gap by hand would leave only a few pixels of
   margin — one font substitution away from cutting again.

   Three across in two rows fits with room to spare, shows all six finishes at
   once, and comes to 90px rather than the 128px the free-form wrap produced.
   --------------------------------------------------------------------------- */

@media (max-width: 620px) {
  [style*="position: fixed"][style*="bottom: 26px"][style*="left: 50%"] {
    /* The bar is pinned with "left: 50%" and centred by a transform. A fixed
       element positioned that way gets its shrink-to-fit width from the space
       between that edge and the viewport's — half the screen, 187px — so the
       columns collapsed below their labels however they were sized, and
       CORTEN / EMERALD / MIDNIGHT ran into each other. Anchoring both edges
       gives it a real 343px to lay out in. */
    left: 16px !important;
    right: 16px !important;
    transform: none !important;
    max-width: none !important;

    display: grid !important;
    /* auto, not 1fr — equal fractions would shrink below the labels again */
    grid-template-columns: repeat(3, auto);
    justify-content: center;
    gap: 4px !important;
  }
  [style*="position: fixed"][style*="bottom: 26px"][style*="left: 50%"] > a {
    white-space: nowrap !important;
    padding: 8px 10px !important;
    text-align: center;
  }
}


/* ---------------------------------------------------------------------------
   4f. THE FORMAT CHIPS (product-line.html)
   The size chips are right-aligned so they sit against the heading opposite
   them on desktop. Once that row wraps on a phone the chips keep hugging the
   right edge, so each one starts at a different indent with empty space down
   the left. Left-aligning them matches every other list on the page.
   --------------------------------------------------------------------------- */

@media (max-width: 620px) {
  [style*="flex-wrap: wrap"][style*="justify-content: flex-end"] {
    justify-content: flex-start !important;
  }
}


/* ---------------------------------------------------------------------------
   4g. THE PROCESS CARDS — "(03) FROM CLAY TO CONTAINER"
   Three problems on a phone, all inherited from the desktop card:

   1. The text sat flush against the left border. The card's grid value is
      "110px 340px 1fr", the same value index.html's list rows use, so the
      page's own rule for those rows — which ends "padding-left: 0" — matched
      the card too. Computed padding came out "48px 56px 48px 0px".
   2. It measured 262px tall for 124px of content: 96px of desktop vertical
      padding plus two 20px row gaps.
   3. A hard 1px rgba(0,0,0,0.2) square-cornered rule reads heavy at this
      size, and these cards physically stack on top of each other, so the
      edge treatment is doing real work.

   Even padding, a hairline border, a soft radius and a shadow that lifts each
   card off the one beneath it as they stack.
   --------------------------------------------------------------------------- */

/* The card surface, at every width. These cards physically stack on top of
   each other as you scroll, so the edge treatment is doing real work: a
   hairline border plus a layered shadow separates the pinned card from the
   one sliding over it in a way a hard square rule cannot. */
[data-stack-card] {
  border: 1px solid rgba(0, 0, 0, 0.08) !important;
  border-radius: 18px !important;
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.04),
    0 12px 28px -14px rgba(0, 0, 0, 0.22) !important;
}

/* Type hierarchy, at every width: the step number recedes, the title tightens,
   the body sits back — so the eye reads number, then title, then description
   instead of three competing weights. Sizes are left to the breakpoints. */
[data-stack-card] > div:first-child {
  letter-spacing: 0.16em !important;
  color: rgba(0, 0, 0, 0.38) !important;
}
[data-stack-card] > h3 {
  letter-spacing: -0.022em !important;
}
[data-stack-card] > p {
  color: rgba(0, 0, 0, 0.58) !important;
}

/* Phones only: the desktop card is a wide three-column row whose 48px/56px
   padding is comfortable at 1344px. At 343px it left the card 262px tall for
   124px of content, so the spacing and the type scale are reset here. */
/* The card's padding-left is destroyed across the WHOLE tablet/laptop range,
   not just on phones. index.html carries its own rule at (max-width: 1099px):

     [style*="grid-template-columns: 110px 340px 1fr"] { padding-left: 0 !important; }

   written for the list rows that share that grid value — and the stack card
   shares it too, so its computed padding becomes "48px 56px 48px 0px" and the
   number, title and body all sit 1px off the border. The rule below used to
   start at 620px, which left 621-1099px broken: every laptop window narrower
   than 1100px showed text hard against the card edge. Restore it for the full
   range first, then let the phone breakpoint tighten it further. */
@media (max-width: 1099px) {
  [data-stack-card] {
    padding: 34px 32px !important;
  }
}

@media (max-width: 620px) {
  [data-stack-card] {
    padding: 26px 22px !important;
    gap: 11px !important;
  }
  [data-stack-card] > div:first-child {
    font-size: 12px !important;
    font-weight: 600 !important;
  }
  [data-stack-card] > h3 {
    font-size: 21px !important;
    line-height: 1.15 !important;
  }
  [data-stack-card] > p {
    font-size: 15.5px !important;
    line-height: 1.55 !important;
    margin-top: 3px !important;
  }
}


/* ---------------------------------------------------------------------------
   4h. THE ABOUT IMAGE BAND
   about.html pins a scroll-scrubbed film (studio.mp4, 1280x720, so 16:9) in a
   frame sized "width: 100%; height: 84vh". On a wide screen that frame works
   out landscape and the film fits exactly. On a 375px phone it measured
   247x682 — an aspect of 0.36 against the source's 1.78 — and object-fit:
   cover threw away about 80% of the picture: a narrow vertical slice of a
   wide showroom.

   The frame now takes the film's own aspect ratio, so nothing is cropped, and
   runs edge to edge to reclaim the 136px the two paddings were eating.

   That leaves the band 211px tall inside a 100vh pinned stage. The pin has to
   stay — stopping the band and scrubbing it as you keep scrolling is the
   whole effect — so instead of removing it, the stage is painted the same
   near-black the frame already uses. The space around the band then reads as
   a cinema surround rather than 300px of blank white, and it matches the
   full-black sections elsewhere on the site.
   --------------------------------------------------------------------------- */

@media (max-width: 620px) {
  [data-studio-scene] {
    height: 240vh !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    background: #191919;
  }
  [data-studio-scene] > div {
    padding-left: 0 !important;
    padding-right: 0 !important;
  }
  [data-studio-scene] > div > div {
    height: auto !important;
    aspect-ratio: 16 / 9;
  }

  /* The caption was a small chip at the bottom-left of a tall frame. Against
     a 211px band, at 12px with 0.2em tracking, it stretched to nearly the
     full width and read as a bar across the building. */
  [data-studio-scene] [style*="bottom: 24px"][style*="left: 26px"] {
    bottom: 12px !important;
    left: 12px !important;
    letter-spacing: 0.1em !important;
    padding: 7px 11px !important;
  }
}


/* ---------------------------------------------------------------------------
   4i. THE DESIGN VIEWER (product-line.html)
   Opening a design fills the screen with a lightbox: header, a stage holding
   the slab, then the size buttons. The stage is

       padding: 40px 90px

   and the frame inside it is

       height: 100%; aspect-ratio: 2 / 1; max-width: 100%

   On a wide screen the stage is roomy and that frame resolves to a landscape
   box the slab sits in comfortably. On a 375px phone the same rules collapse:
   180px of the 375 goes to side padding, leaving 195px, and because the frame
   is driven from its height the 2/1 ratio wants 846px of width and is then
   clamped back to 195. The slab — a 1600x533 image, so 3:1 — ends up rendered
   at 195 x 65 in the middle of an 812px screen.

   Trimming the padding and letting the frame take its width from the stage
   rather than its height puts the slab at 335 x 112, near three times the
   area, with its own 3:1 ratio intact.
   --------------------------------------------------------------------------- */

@media (max-width: 620px) {
  [style*="padding: 40px 90px"] {
    padding: 24px 20px !important;
  }
  [style*="height: 100%"][style*="aspect-ratio: 2 / 1"] {
    height: auto !important;
    width: 100% !important;
    aspect-ratio: auto !important;
  }
}


/* ---------------------------------------------------------------------------
   5. TYPE FLOOR
   Body and label text below 12px is not comfortably readable on a phone.
   carvotech and product-line each carry 75+ elements at 10.5px; contact has
   17 at 9.5px. Tracking is eased off a little at the same time, since the
   wide letter-spacing on these small uppercase labels costs more width than
   it earns at this size.
   --------------------------------------------------------------------------- */

@media (max-width: 620px) {
  [style*="font-size: 8px"],
  [style*="font-size: 8.5px"],
  [style*="font-size: 9px"],
  [style*="font-size: 9.5px"],
  [style*="font-size: 10px"],
  [style*="font-size: 10.5px"],
  [style*="font-size: 11px"],
  [style*="font-size: 11.5px"] {
    font-size: 12px !important;
  }

  [style*="font-size: 9px"][style*="letter-spacing: 0.2"],
  [style*="font-size: 9.5px"][style*="letter-spacing: 0.2"],
  [style*="font-size: 10px"][style*="letter-spacing: 0.2"],
  [style*="font-size: 10.5px"][style*="letter-spacing: 0.2"] {
    letter-spacing: 0.12em !important;
  }

  /* Body copy sits at a comfortable measure rather than the desktop 16px/1.65
     in a narrow column. */
  p { line-height: 1.6; }
}


/* ---------------------------------------------------------------------------
   6. TOUCH TARGETS
   Small links keep their visual size — the tap area is extended underneath
   with a pseudo-element, so nothing moves but the target reaches 44px.
   --------------------------------------------------------------------------- */

@media (max-width: 1099px) {
  [data-lang],
  footer a,
  nav a,
  [data-nav] a {
    position: relative;
  }

  [data-lang]::after,
  footer a::after,
  nav a::after,
  [data-nav] a::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: max(100%, 44px);
    height: max(100%, 44px);
    transform: translate(-50%, -50%);
  }

  /* the two language buttons measured 22x18 */
  [data-lang] { padding: 4px 6px !important; }

  /* inline "+ ADD SAMPLE" / "View finish" affordances.

     Never applied to a control that declares its own height. index.html's
     carousel progress bar is six buttons with an inline "height: 5px" — thin
     segments along the bottom edge of the slide. A blanket min-height turned
     each into a 40px white block at z-index 4, sitting on top of the caption
     and hiding the tile name. The :not() tests match the height property
     itself, not line-height or max-height. */
  button:not([style*="; height:"]):not([style^="height:"]),
  a[role="button"]:not([style*="; height:"]):not([style^="height:"]) {
    min-height: 40px;
  }
}


/* ---------------------------------------------------------------------------
   7. VIEWPORT HEIGHT
   100vh is measured against the viewport with the mobile URL bar retracted,
   so a 100vh section is taller than what the user can actually see and the
   bottom of it is cut off. dvh tracks the visible area instead.
   --------------------------------------------------------------------------- */

@supports (height: 100dvh) {
  @media (max-width: 1099px) {
    /* The leading "; " matters. "height: 100vh" is a substring of
       "min-height: 100vh", so a bare [style*="height: 100vh"] also matches
       index.html's hero and turns its soft 100vh floor into a hard 812px
       height — which is what was cutting the tile carousel off. Every real
       "height: 100vh" in the markup follows a semicolon; the hero's does not. */
    [style*="; height: 100vh"] { height: 100dvh !important; }

    /* Not the hero flex column: section 3b deliberately drops its 100vh floor
       so the column can size to its content, and this rule sits later in the
       file, so without the exclusion it would put the floor straight back. */
    [style*="min-height: 100vh"]:not([style*="display: flex"]) {
      min-height: 100dvh !important;
    }
  }
}


/* ---------------------------------------------------------------------------
   8. OVERFLOW GUARDS
   A last line of defence: nothing may make the document wider than the screen.
   --------------------------------------------------------------------------- */

@media (max-width: 1099px) {
  /* Deliberately no overflow-x here.

     A first pass set it on <html> and <body>, which broke two things. On
     <body> it makes body its own scroll container, so its height stops
     propagating to <html> and documentElement.scrollHeight sticks at one
     viewport. On <html> it is subtler: carvotech.html's own stylesheet sets
     "body { overflow-x: hidden }" and relies on that propagating up to the
     viewport, which only happens while <html> is overflow:visible. Clipping
     at the root cancels the propagation, body becomes a real scroller pinned
     to 812px, and the scroll-scrubbed video engine reads its position from a
     document that no longer scrolls.

     The layout fixes above are what stop the sideways scroll — every page now
     measures documentElement.scrollWidth === innerWidth — so the blunt guard
     is not needed, and each page already carries its own. */
  html, body { max-width: 100%; }

  img, video, iframe, canvas, svg {
    max-width: 100% !important;
    height: auto;
  }

  /* full-bleed art that is deliberately pulled past the gutter still may not
     push the page sideways — carvotech's #gris image sat 3px off the left
     edge and 3px past the right */
  section > img,
  [data-screen-label] img {
    max-width: 100% !important;
  }

  /* long unbroken strings (email addresses, URLs) */
  a, p, li, td, h1, h2, h3, h4 {
    overflow-wrap: anywhere;
  }
}


/* ---------------------------------------------------------------------------
   8a. STICKY SCROLL EFFECTS KILLED BY THE OVERFLOW GUARD
   Every page's own mobile block contains

       [data-screen-label] { overflow-x: hidden !important; }

   as a sideways-scroll guard. But overflow-x: hidden forces overflow-y to
   compute to auto, which turns each section into a scroll container — and a
   position: sticky element only sticks inside its nearest scrolling ancestor.
   On index.html the six "(03) From clay to container" cards stick to
   SECTION[Process], which never scrolls, so the cards never pin and the
   scale-and-dim effect that runs on desktop does nothing on a phone.

   overflow-x: clip clips just as well but does not establish a scroll
   container, so overflow-y stays visible and sticky works against the
   viewport again. Guarded by @supports; browsers without clip keep the old
   behaviour rather than losing the sideways guard.
   --------------------------------------------------------------------------- */

@supports (overflow-x: clip) {
  @media (max-width: 1099px) {
    [data-screen-label] {
      overflow-x: clip !important;
      overflow-y: visible !important;
    }
  }
}


/* ---------------------------------------------------------------------------
   8b. POINTER-ONLY CHROME
   The cursor-follow preview is a 460px fixed panel that tracks the mouse.
   Seven of the nine pages already hide it on small screens; responsibility.html
   and privacy.html were missed, leaving the panel in the layout. It has no
   purpose on a touch device either way.
   --------------------------------------------------------------------------- */

@media (max-width: 1099px), (pointer: coarse) {
  [data-preview-layer] { display: none !important; }
}


/* ---------------------------------------------------------------------------
   8c. THE DESIGN LIBRARY GRID
   product-line.html lists 72 designs down a 21,000px page. The images carry
   loading="lazy" but it does not take effect: the grid is rendered
   client-side and the framework assigns src before the attribute lands, so
   all 72 are fetched in the first second regardless.

   That is addressed in the markup instead, by serving 700px thumbnails (see
   the srcset on those <img> tags) rather than the 1400px originals — 8.0MB
   down to 3.0MB. This rule is a separate, smaller win: content-visibility
   lets the browser skip layout and paint for off-screen cards, which keeps
   scrolling smooth on a 21,000px page. contain-intrinsic-size supplies the
   card height so the scrollbar stays honest. It does not defer any fetch.
   --------------------------------------------------------------------------- */

[data-screen-label="Designs"] > [style*="grid-template-columns"] > button {
  content-visibility: auto;
  contain-intrinsic-size: auto 222px;
}


/* ---------------------------------------------------------------------------
   8d. ARROWS MUST NOT BECOME EMOJI
   "SEE THE WORK ↗", "LET'S TALK ↗" and the rest use U+2197. That character
   is Emoji=Yes, so when the page font has no glyph for it — Manrope does not
   — iOS falls through the stack to Apple Color Emoji and paints a blue
   rounded tile instead of a thin arrow. Reported from a real iPhone.

   The markup now carries U+FE0E (variation selector-15) after each such
   glyph, which is the part that actually fixes it; 55 of them across the nine
   pages, covering ↗, ↔, ▶ and ◀. ←, → and ↓ have no emoji form and are left
   alone.

   This rule is the backstop for engines that support it: it asks for text
   presentation for the whole run, so a glyph added later without the selector
   still resolves monochrome. Ignored where unsupported, which is why the
   selector in the markup is not optional.
   --------------------------------------------------------------------------- */

body, button, a, h1, h2, h3, h4, p, span, div, li {
  font-variant-emoji: text;
}


/* ---------------------------------------------------------------------------
   8e. "NINE EXPRESSIONS OF CARVOTECH" — DESKTOP ONLY
   The colour explorer is a grid, "1fr 280px", holding a preview frame beside
   the swatch list. The frame carries "aspect-ratio: 16 / 9" and the grid is
   "align-items: stretch".

   Browsers resolve that pairing differently. Chromium sizes the item from its
   column — 1046px wide, height derived from the ratio, 588px — and the row
   grows to match. Safari stretches the item to the row height first, and the
   row is only as tall as the swatch list (~282px), so the ratio is applied in
   reverse and yields 282 x 16/9 = about 500px wide. The preview came out at
   roughly a third of its intended size with a wide band of empty black beside
   it.

   Pinning the frame's width and opting it out of the stretch removes the
   ambiguity: the width is now stated, so both engines derive the height from
   the ratio and agree.

   Scoped to the desktop canvas on purpose. Below 1100px the grid is already
   collapsed to a single column, so mobile is untouched.
   --------------------------------------------------------------------------- */

@media (min-width: 1100px) {
  [style*="grid-template-columns: 1fr 280px"][style*="align-items: stretch"] > [style*="aspect-ratio: 16 / 9"] {
    width: 100%;
    align-self: start;
  }
}


/* ---------------------------------------------------------------------------
   9. MOTION
   The scroll-scrubbed video and reveal animations are decorative.
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  [data-words] span > span { transform: none !important; }
}

/* ---------------------------------------------------------------------------
   4j. THE RANGE — stat row (about.html)
   Four large numbers in a row on desktop. At phone widths four columns give
   each figure about 70px, which forces the labels to wrap to four lines and
   the numbers to shrink below the point of being a statement — so it drops
   to two columns and the type scales with it.
   --------------------------------------------------------------------------- */
@media (max-width: 900px) {
  [data-range-stats] {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    gap: 40px 28px !important;
  }
}
@media (max-width: 460px) {
  [data-range-stats] { gap: 32px 22px !important; }
  [data-range-stats] > div > div:first-child { font-size: 42px !important; }
}

/* ---------------------------------------------------------------------------
   4k. DESIGN SEARCH (product-line.html)
   iOS Safari zooms the page in whenever a focused input has a font-size below
   16px, which throws the whole grid sideways the moment someone taps the
   search field. 16px is the threshold, not a preference — do not reduce it.
   The bar also goes full width on a phone; a 460px cap looks stranded there.
   --------------------------------------------------------------------------- */
@media (max-width: 1099px) {
  [data-design-search] input { font-size: 16px !important; }
}
@media (max-width: 620px) {
  [data-design-search] {
    max-width: none !important;
    margin-bottom: 20px !important;
  }
}

/* ---------------------------------------------------------------------------
   4l. HAIRLINE GRIDS — do not inflate a 1-2px gap
   Several grids draw their dividers as the GAP: the cells are opaque and the
   grid's own translucent background shows through a 1px or 2px gutter. The
   per-page blocks collapse every inline grid and set "gap: 22px !important",
   which cannot tell a divider from spacing — so on a phone the Craft stat
   block rendered four 22px slabs of grey between the figures instead of
   hairlines. Pin the small gaps back.

   Affects: index (Craft stats), products, carvotech, responsibility,
   company-profile. Equal specificity to the per-page rule, but mobile.css is
   linked after it, so source order decides in our favour.
   --------------------------------------------------------------------------- */
@media (max-width: 1099px) {
  [style*="gap: 1px"] { gap: 1px !important; }
  [style*="gap: 2px"] { gap: 2px !important; }
}

/* ---------------------------------------------------------------------------
   4m. PROCESS CARDS — cap the measure on desktop
   The card grid is "110px 340px 1fr", so the body paragraph takes every pixel
   left over. On a 1440px screen that is a 692px column carrying the whole
   sentence on ONE line at 83 characters — it reads as text running edge to
   edge, and it gets worse on a wider monitor. A comfortable measure is 60-75
   characters, so the body is capped and wraps to two short lines instead.
   The card itself still spans the full width, which is the intended look.
   --------------------------------------------------------------------------- */
@media (min-width: 1100px) {
  [data-stack-card] > p {
    max-width: 60ch;
  }
}
