/* ============================================================================
   mobile.css — responsive repair layer for the Claude design exports
   ----------------------------------------------------------------------------
   Directions 02–08 were composed in Claude design at a fixed 1480px canvas and
   exported with every rule as an inline style attribute. They contain no media
   queries at all, so at 375px they keep their desktop geometry and the page
   scrolls sideways.

   The three faults, in order of damage:

     1. Flex rows that cannot shrink. A row of fixed-size children reports a
        min-content width far wider than the phone (one measured 668px inside a
        375px page). Children need min-width:0 before they will ever shrink.
     2. Grids with pixel column tracks (e.g. 114px 337px 96px) that keep those
        tracks regardless of available width.
     3. Media and fixed-width boxes with no max-width ceiling.

   Because the source styles are inline, overriding them requires !important —
   inline styles otherwise win every cascade contest. That is a deliberate
   choice here, not carelessness: this file exists to override a generator.

   Attribute selectors match the generator's own formatting (`display:flex;`
   with no space). Both spaced and unspaced forms are matched so the layer keeps
   working if the export format changes.

   Loaded AFTER the page's own <style> block, from each direction's index.html.
   ========================================================================== */

@media (max-width: 820px) {

  /* --- 1. containment ---------------------------------------------------- */

  html, body {
    max-width: 100% !important;
    overflow-x: hidden !important;   /* backstop only; the rules below remove
                                        the actual causes, so this should never
                                        be what is doing the work */
    overflow-x: clip !important;     /* iOS Safari lets the user PAN a body that
                                        merely hides its overflow — hidden makes
                                        a scroll container, and touch can drive
                                        it even with no scrollbar. clip forbids
                                        scrolling outright, which is what killed
                                        the sideways panning seen on Alex's
                                        phone. hidden above stays as the
                                        fallback for engines without clip. */
  }

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

  svg { max-width: 100% !important; }

  /* --- 2. flex rows must wrap and their children must be able to shrink --- */

  [style*="display:flex"],
  [style*="display: flex"] {
    flex-wrap: wrap !important;
    max-width: 100% !important;
  }

  /* The single most important rule in this file. A flex or grid child defaults
     to min-width:auto, which resolves to its content width and makes the row
     refuse to shrink. */
  [style*="display:flex"] > *,
  [style*="display: flex"] > *,
  [style*="display:grid"] > *,
  [style*="display: grid"] > * {
    min-width: 0 !important;
  }

  /* --- 2b. EXCEPTION: width:max-content strips must never wrap ------------ */

  /* The exports use `display:flex; width:max-content` for exactly one thing:
     a deliberately overwide horizontal strip inside a clipping or scrolling
     parent — the press-name marquees in 02/03/08 (animated with translateX),
     Atelier's drag-gallery, Aperture's filmstrip. Rule 2's blanket flex-wrap
     folded these into vertical stacks up to 2,700px tall: the "scattered
     press names" and "images sitting on text" wreckage Alex photographed.
     Their parents already clip (marquees) or scroll (galleries), so the right
     mobile treatment is the desktop one: a single row, overflow contained. */
  [style*="width:max-content"],
  [style*="width: max-content"] {
    flex-wrap: nowrap !important;
    max-width: none !important;
  }

  /* ...and so must everything inside one. The marquees hold two copies of the
     name row, each itself a plain flex row that rule 2 would wrap internally
     into a ragged multi-line block. Nothing inside a deliberate overwide strip
     may wrap or be width-capped. */
  [style*="width:max-content"] > *,
  [style*="width: max-content"] > *,
  [style*="width:max-content"] [style*="display:flex"],
  [style*="width: max-content"] [style*="display: flex"] {
    flex: 0 0 auto !important;
    flex-wrap: nowrap !important;
    max-width: none !important;
  }

  /* --- 2c. bare image rows: the one max-content case that must NOT stay a
     row. Vault pairs two 200px photographs and Aperture strips four, both as
     `width:max-content` flex rows of bare <img> with NO clipping or scrolling
     parent — on a phone they overflow the screen (403px and 808px). These
     become a two-column grid: every photograph visible, nothing off-screen,
     and at ~180px each they read as a deliberate collage. Animated marquees
     and card galleries (div children) are excluded and keep rule 2b. */
  [style*="width:max-content"]:not([style*="animation"]):has(> img:first-child),
  [style*="width: max-content"]:not([style*="animation"]):has(> img:first-child) {
    display: grid !important;
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    width: auto !important;
    max-width: 100% !important;
  }

  [style*="width:max-content"]:not([style*="animation"]):has(> img:first-child) > img,
  [style*="width: max-content"]:not([style*="animation"]):has(> img:first-child) > img {
    width: 100% !important;
    height: auto !important;
    aspect-ratio: 1 / 1;
    object-fit: cover;
  }

  /* --- 3. desktop grids collapse to a single column ---------------------- */

  [style*="grid-template-columns"] {
    grid-template-columns: 1fr !important;
    max-width: 100% !important;
  }

  /* --- 3a. sticky columns must stop being sticky ------------------------- */

  /* Every export builds its product page as two columns — a gallery that is
     `position:sticky; top:80-120px` beside a scrolling specification column.
     Rule 3 collapses that grid to one column, but the gallery stayed sticky,
     and a sticky element is constrained by its CONTAINING BLOCK (the whole
     grid), not by its own row. So the gallery slid up to 1,398px down out of
     row one and came to rest on top of the specification text — and being a
     positioned element, it painted over it. That is the "pale text behind the
     images, not scrolling quite right" Alex photographed on direction 02.

     Why it appeared only after the D-018 pass: the old `overflow-x:hidden`
     backstop computed body's overflow-y to `auto`, making body a scroll
     container, which silently disabled every sticky descendant. Switching to
     `overflow-x:clip` — correct, and necessary to stop iOS panning — creates
     no scroll container, so sticky came back to life and the latent fault
     became visible. The fault was always in the layout; hidden was hiding it.

     Sticky exists to hold one column while another scrolls past. In a single
     column there is nothing to hold it against, so it goes back to static. */
  [style*="position:sticky"],
  [style*="position: sticky"] {
    position: static !important;
    top: auto !important;
  }

  /* --- 3b. the navigation bar ------------------------------------------- */

  /* Six of the seven exports build their header as the same three-column grid
     — brand | links | actions — with a fixed pixel height. Collapsing that to
     one column (rule 3 above) stacks it into three tall rows that swallow a
     quarter of the screen, and the fixed height then clips it.

     Instead: brand and actions share row one, the links become row two as a
     single horizontally scrollable strip. Two compact rows, nothing clipped,
     every link still reachable.

     These rules must follow rule 3 — same specificity, so source order decides
     which wins. */
  /* The nav stops floating on phones.

     Every direction offsets its first section to clear a fixed nav that is
     56–70px tall on a desktop. The two-row mobile nav is ~89px, so it sat on
     top of the first block of content on every page — the specification strip
     in direction 07 lost 34px of its label row that way. Rather than retune six
     different content offsets against a nav height that varies per direction
     and per phone width, the nav simply joins the flow on small screens and
     scrolls away with the page. It cannot overlap anything it is not on top of.

     :has() selects the fixed wrapper by the grid it contains, since the wrapper
     itself carries no class. */
  *:has(> [style*="grid-template-columns:1fr auto 1fr"]),
  *:has(> [style*="grid-template-columns: 1fr auto 1fr"]) {
    position: static !important;
  }

  /* Direction 02 insets its nav as a floating pill (top:18px); keep that
     breathing room now that it sits in the flow. The others are full-bleed
     bars with a bottom border and want no gap above them. */
  [style*="top:18px"]:has(> [style*="grid-template-columns: 1fr auto 1fr"]),
  [style*="top: 18px"]:has(> [style*="grid-template-columns: 1fr auto 1fr"]) {
    padding-top: 14px !important;
  }

  /* NOTE ON SPELLING: these pages are rendered by React, which re-serialises
     every inline style with a space after the colon — the source says
     `grid-template-columns:1fr auto 1fr`, the live DOM says
     `grid-template-columns: 1fr auto 1fr`. Attribute substring selectors are
     literal, so each value-bearing selector below is written both ways. Only
     the spaced form matches today; the unspaced form is kept so the layer still
     works if the runtime ever stops normalising. */
  [style*="grid-template-columns:1fr auto 1fr"],
  [style*="grid-template-columns: 1fr auto 1fr"] {
    grid-template-columns: 1fr auto !important;
    height: auto !important;
    min-height: 0 !important;
    padding-top: 9px !important;
    padding-bottom: 9px !important;
    padding-left: 14px !important;
    padding-right: 14px !important;
    gap: 7px 10px !important;
  }

  [style*="grid-template-columns:1fr auto 1fr"] > *:nth-child(1),
  [style*="grid-template-columns: 1fr auto 1fr"] > *:nth-child(1) {
    grid-column: 1; grid-row: 1;
  }

  [style*="grid-template-columns:1fr auto 1fr"] > *:nth-child(3),
  [style*="grid-template-columns: 1fr auto 1fr"] > *:nth-child(3) {
    grid-column: 2; grid-row: 1;
    justify-content: flex-end !important;
  }

  [style*="grid-template-columns:1fr auto 1fr"] > *:nth-child(2),
  [style*="grid-template-columns: 1fr auto 1fr"] > *:nth-child(2) {
    grid-column: 1 / -1; grid-row: 2;
    flex-wrap: nowrap !important;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 18px !important;
    padding-bottom: 1px;
    /* The strip scrolls, and the scrollbar is hidden, so the last link can sit
       just off the edge with nothing to say so. This fades the right edge as a
       hint that there is more. When the links do fit, the fade lands on empty
       space and is invisible — so it costs nothing to apply unconditionally. */
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent 100%);
  }

  [style*="grid-template-columns:1fr auto 1fr"] > *:nth-child(2)::-webkit-scrollbar,
  [style*="grid-template-columns: 1fr auto 1fr"] > *:nth-child(2)::-webkit-scrollbar {
    display: none;
  }

  /* links must not shrink or wrap mid-word inside the scrolling strip */
  [style*="grid-template-columns:1fr auto 1fr"] > *:nth-child(2) > *,
  [style*="grid-template-columns: 1fr auto 1fr"] > *:nth-child(2) > * {
    flex: 0 0 auto !important;
    white-space: nowrap !important;
  }

  /* --- 3c. five- and six-column strips ----------------------------------- */

  /* The exports use repeat(5/6, 1fr) grids two different ways, and each needs
     a different mobile treatment. The previous approach here — keep the
     columns at 108px and scroll the strip sideways — put horizontal scrolling
     inside vertical pages, which Alex reported as breakage, and 108px tracks
     broke words like "Impulse" in half. Both treatments below fit the
     viewport; nothing scrolls sideways any more.

     Classifying the two: a CARD cell holds block content (divs, images); a
     LEAF cell holds only text or inline sc-interp spans. `:has(> * > div)`
     detects block grandchildren — plain `> * > *` does not work, because the
     runtime wraps interpolated text in <span class=sc-interp>, which made
     value rows read as cards.

     Case 1 — card grids (image + caption, or label + value inside one cell):
     reflow to two columns. Pairing lives inside each cell; nothing is lost,
     and ~160px columns fit every word these cells hold. */
  [style*="repeat(5, 1fr)"]:has(> * > div), [style*="repeat(5, 1fr)"]:has(> * > img),
  [style*="repeat(5,1fr)"]:has(> * > div),  [style*="repeat(5,1fr)"]:has(> * > img),
  [style*="repeat(6, 1fr)"]:has(> * > div), [style*="repeat(6, 1fr)"]:has(> * > img),
  [style*="repeat(6,1fr)"]:has(> * > div),  [style*="repeat(6,1fr)"]:has(> * > img) {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }

  /* Case 2 — a row of leaf labels with a sibling row of leaf values under it
     (direction 07's header band and spec strips). Stacking either row loses
     the label↔value pairing, and CSS cannot interleave two containers.
     Attempts that do not work, recorded so nobody retries them:
       - :has() nested inside :has() is invalid and the rule is silently
         dropped (first attempt);
       - display:contents into the shared parent only works when the parent
         holds nothing but the two grids — here it is the whole sheet, and
         column-flow grid on it shredded the page (second attempt).
     What does work: both grids become single-column with the SAME fixed row
     height; the label grid floats left at 40% and the value grid, a grid
     container and therefore a BFC, lays out beside it. Fixed rows keep label
     i and value i level. Values here are short structured facts — two lines
     at these sizes fit 54px, and cells clip rather than desync. */
  [style*="repeat(5, 1fr)"]:not(:has(> * > div)):not(:has(> * > img)):has(+ [style*="repeat(5, 1fr)"]),
  [style*="repeat(5,1fr)"]:not(:has(> * > div)):not(:has(> * > img)):has(+ [style*="repeat(5,1fr)"]),
  [style*="repeat(6, 1fr)"]:not(:has(> * > div)):not(:has(> * > img)):has(+ [style*="repeat(6, 1fr)"]),
  [style*="repeat(6,1fr)"]:not(:has(> * > div)):not(:has(> * > img)):has(+ [style*="repeat(6,1fr)"]) {
    float: left;
    width: 40%;
    grid-template-columns: 1fr !important;
    grid-auto-rows: 54px;
    border-bottom: 0 !important;
  }

  [style*="repeat(5, 1fr)"]:not(:has(> * > div)) + [style*="repeat(5, 1fr)"]:not(:has(> * > div)):not(:has(> * > img)),
  [style*="repeat(5,1fr)"]:not(:has(> * > div)) + [style*="repeat(5,1fr)"]:not(:has(> * > div)):not(:has(> * > img)),
  [style*="repeat(6, 1fr)"]:not(:has(> * > div)) + [style*="repeat(6, 1fr)"]:not(:has(> * > div)):not(:has(> * > img)),
  [style*="repeat(6,1fr)"]:not(:has(> * > div)) + [style*="repeat(6,1fr)"]:not(:has(> * > div)):not(:has(> * > img)) {
    overflow: hidden;              /* BFC: sits beside the float, never under */
    grid-template-columns: 1fr !important;
    grid-auto-rows: 54px;
  }

  /* cells of both paired grids: center vertically, clip, one shared rhythm */
  [style*="repeat(5, 1fr)"]:not(:has(> * > div)):has(+ [style*="repeat(5, 1fr)"]) > *,
  [style*="repeat(5, 1fr)"]:not(:has(> * > div)) + [style*="repeat(5, 1fr)"]:not(:has(> * > div)) > *,
  [style*="repeat(6, 1fr)"]:not(:has(> * > div)):has(+ [style*="repeat(6, 1fr)"]) > *,
  [style*="repeat(6, 1fr)"]:not(:has(> * > div)) + [style*="repeat(6, 1fr)"]:not(:has(> * > div)) > * {
    display: flex !important;
    align-items: center !important;
    overflow: hidden;
    padding: 8px 10px !important;
    border-right: 0 !important;
    border-bottom: 1px solid rgba(128, 128, 128, 0.18) !important;
  }

  /* whatever follows the pair starts on a fresh line */
  [style*="repeat(5, 1fr)"] + [style*="repeat(5, 1fr)"] + *,
  [style*="repeat(6, 1fr)"] + [style*="repeat(6, 1fr)"] + * {
    clear: both;
  }


  /* --- 3d. CSS multi-column text ---------------------------------------- */

  /* Direction 06 sets its essay in three newspaper columns. On a 335px phone
     that leaves each column 77px wide — six characters a line, roughly one word
     per line, which is unreadable. Multi-column is a desktop-width idea; on a
     phone the viewport IS the column. */
  [style*="columns:"], [style*="columns :"],
  [style*="column-count"] {
    columns: 1 !important;
    column-count: 1 !important;
    column-gap: 0 !important;
    column-rule: none !important;
  }

  /* --- 3e. NOT DONE: forcing a minimum width on flex content blocks -------

     Attempted and reverted. Direction 08 has a paragraph sharing a wrapping
     flex row with a sibling, so it renders about 205px wide — roughly 22
     characters a line, tighter than it should be. The obvious fix,

         [style*="display:flex"] > div { flex: 1 1 240px !important }

     does not work, because an attribute selector cannot tell a flex ROW from a
     flex COLUMN. In a column, flex-basis sets height, so the rule squashed
     content on direction 02 — it went from zero narrow blocks to three while
     direction 08 did not improve at all. Net worse.

     Left alone deliberately. Direction 08 is the superseded first revision of
     Signal, kept for reference only, and the remaining case is tight rather
     than broken. A real fix means editing that one card's markup, which is
     worth doing only if 08 stops being an also-ran.
     ---------------------------------------------------------------------- */

  /* --- 4. long unbroken strings (part codes, URLs, spec values) ---------- */

  body {
    overflow-wrap: break-word;
    word-break: normal;
  }

  /* --- 5. tame the desktop rhythm --------------------------------------- */

  /* The exports pad sections to 130px+ vertically and up to 90px horizontally,
     which on a 375px screen leaves almost no line length. Scale the worst of
     it back without flattening the design's sense of space. */
  [style*="padding:100px"], [style*="padding: 100px"],
  [style*="padding:104px"], [style*="padding: 104px"],
  [style*="padding:110px"], [style*="padding: 110px"],
  [style*="padding:120px"], [style*="padding: 120px"],
  [style*="padding:130px"], [style*="padding: 130px"],
  [style*="padding:140px"], [style*="padding: 140px"],
  [style*="padding:150px"], [style*="padding: 150px"],
  [style*="padding:160px"], [style*="padding: 160px"],
  [style*="padding:170px"], [style*="padding: 170px"],
  [style*="padding:180px"], [style*="padding: 180px"],
  [style*="padding:210px"], [style*="padding: 210px"] {
    /* the nav is in the flow on mobile now, so this no longer has to reserve
       space for it — it only needs to be a sensible section rhythm */
    padding-top: 44px !important;
    padding-bottom: 40px !important;
  }

  /* --- 5b. page gutters -------------------------------------------------- */

  /* The full-width wrappers carry the desktop gutter (up to 48px a side),
     which on a 375px screen leaves a 270px column — narrow enough that a word
     like "Loudspeakers" no longer fits its own headline. These are the design
     canvases, identified by their max-width, so pulling their gutters in is
     precise rather than a blanket padding reset. */
  [style*="max-width:1180px"], [style*="max-width: 1180px"],
  [style*="max-width:1480px"], [style*="max-width: 1480px"],
  [style*="max-width:1500px"], [style*="max-width: 1500px"],
  [style*="max-width:1560px"], [style*="max-width: 1560px"],
  [style*="max-width:1600px"], [style*="max-width: 1600px"],
  [style*="max-width:1640px"], [style*="max-width: 1640px"] {
    padding-left: 20px !important;
    padding-right: 20px !important;
  }

  /* --- 5c. headline sizes ------------------------------------------------ */

  /* Every headline is a clamp, but the floors were chosen for a 1480px canvas:
     a floor of 40–58px cannot fit in a phone column, and the browser then
     breaks the word rather than the line. Only floors of 40px and above are
     touched — smaller headings already fit and keep each direction's own
     typographic scale intact. */
  [style*="clamp(40px"], [style*="clamp(42px"], [style*="clamp(44px"],
  [style*="clamp(46px"], [style*="clamp(48px"], [style*="clamp(58px"] {
    font-size: clamp(29px, 8.4vw, 46px) !important;
  }

  /* callout cards padded 80px 60px keep a 215px text column on a phone —
     direction 08's orange card was the reported case */
  [style*="padding:80px 60px"], [style*="padding: 80px 60px"] {
    padding: 40px 24px !important;
  }

  [style*="padding-left:90px"], [style*="padding-left: 90px"],
  [style*="padding-right:90px"], [style*="padding-right: 90px"],
  [style*="padding:0 90px"], [style*="padding: 0px 90px"],
  [style*="padding:0 80px"], [style*="padding: 0px 80px"],
  [style*="padding:0 70px"], [style*="padding: 0px 70px"] {
    padding-left: 20px !important;
    padding-right: 20px !important;
  }

  /* --- 5d. a readable floor for label type ------------------------------- */

  /* The exports set captions, eyebrows and plate labels at 8–9.5px. On a
     1480px desktop canvas that reads as fine editorial detail; on a phone held
     at arm's length it is a grey smudge, and a client swiping through the demo
     simply cannot read it. The audit found 73 such labels across directions
     03, 04 and 07. Lifting only the sub-10px sizes to 10.5px keeps every
     deliberate size relationship above that floor intact — the labels stay the
     smallest type on the page, they are merely legible now.

     Each size is written out in full rather than as a `font-size:9` prefix:
     the prefix form would also match a hypothetical 90px or 96px headline and
     shrink it to nothing. Only the four sub-10px values the exports actually
     use are listed. */
  [style*="font-size:8px"],   [style*="font-size: 8px"],
  [style*="font-size:8.5px"], [style*="font-size: 8.5px"],
  [style*="font-size:9px"],   [style*="font-size: 9px"],
  [style*="font-size:9.5px"], [style*="font-size: 9.5px"] {
    font-size: 10.5px !important;
  }

  /* --- 6. tap targets ---------------------------------------------------- */

  a, button, [onClick], [role="button"] {
    touch-action: manipulation;
  }
}

/* Very small phones (iPhone SE and similar) need the gutters pulled in
   further or headlines lose too many characters per line. */
@media (max-width: 380px) {
  [style*="padding:0 22px"], [style*="padding: 0px 22px"],
  [style*="padding:0 24px"], [style*="padding: 0px 24px"] {
    padding-left: 14px !important;
    padding-right: 14px !important;
  }

  /* NOT DONE, second attempt (after D-015's first): giving flex children
     that carry a paragraph `flex-basis:100%` to stop two shrinkable siblings
     squeezing each other at 320px. A percentage basis is harmless in flex
     columns, but `> :has(p)` also catches children of NOWRAP rows (marquees,
     galleries), where basis:100% re-widens the page — p2 went from 310px to
     429px of scroll. Reverted; the remaining cost is two paragraphs at
     ~150px on 320px phones (directions 02 and 08), readable and cosmetic. */
}
