/*
 * Mobile refinement for Influex's design.
 *
 * Their site was authored on a fixed 1920 stage, so small screens were never a
 * layout problem for it — every size is an absolute px value chosen for that
 * canvas. On a 390px phone the consequences are measurable: /home's wordmark is
 * 658px wide at 72px, /contact's hero is 726px at 100px, and the document
 * scrolls sideways by up to 370px. A page wider than the phone is also why the
 * header appears to float: it is correctly 390px and anchored, and the page
 * slides underneath it.
 *
 * EVERYTHING HERE IS INSIDE A max-width MEDIA QUERY, deliberately. Desktop is
 * proven pixel-identical to the frozen original and tablet measures zero
 * overflow, so neither may move. Rules that do not exist above 780px cannot
 * disturb them — the guarantee is structural rather than a promise to be
 * careful.
 *
 * Influex owns the design. This makes their composition fit a phone; it does
 * not restyle it. Type scale, colour, imagery and rhythm are theirs, and the
 * small-screen result is for their team to refine.
 */

@media (max-width: 780px) {

  /* ---- 1. Display type becomes fluid --------------------------------------
   * Each clamp keeps their original size as its ceiling, so nothing shrinks
   * until the viewport genuinely cannot hold it. The vw middle value is what
   * makes a long wordmark fit instead of running off the screen.            */

  /* .wordmark is 13vw where the others are 11vw.
   *
   * 11vw was tuned to hold "Wielding Magic" on one line, which it never
   * managed. Now that it wraps to two words, the longer of them is "Wielding"
   * and the line is far shorter, so the same value leaves the headline filling
   * 67% of its box: measurably under-set for a hero wordmark. 13vw takes it to
   * about 80% and stops short of the edge, which is the margin a longer word
   * than Ted's current one needs before the last resort above is reached.
   * 72px, their original size, is still the ceiling. */
  h1.wordmark            { font-size: clamp(28px, 13vw, 72px)  !important; }
  span.ink-sans,
  h1.c-display           { font-size: clamp(30px, 13vw, 100px) !important; }
  span.nf-digit          { font-size: clamp(64px, 26vw, 150px) !important; }
  h1.pp-hero__title      { font-size: clamp(28px, 11vw, 72px)  !important; }
  h2.lp-banner__title,
  h2.c-display           { font-size: clamp(26px, 9.5vw, 64px) !important; }
  h2.lph-title           { font-size: clamp(24px, 8.5vw, 56px) !important; }
  h1.wk2-wordmark        { font-size: clamp(24px, 8vw, 52px)   !important; }
  h1.wgd-hero__title,
  h2.flib__title         { font-size: clamp(22px, 7.5vw, 46px) !important; }
  h2.cine-line,
  h2.ins-head,
  h2.fp-reels__title,
  h2.mp-head__title,
  h2.wk2-close__title    { font-size: clamp(22px, 7vw, 44px)   !important; }

  /* Headlines wrap at spaces, never inside a word.
   *
   * `word-break: break-word` split "WIELDING MAGIC" into "WIELDING MAG / IC",
   * chopping the word instead of using the space sitting right there. Only
   * `overflow-wrap: anywhere` is kept, and it is the last resort: it applies
   * to a single unbroken word too long for the screen, and never in preference
   * to an ordinary space.
   *
   * `hyphens` is off. Their display faces are set in caps for effect and an
   * inserted hyphen reads as a typo in that context. */
  h1, h2, .wordmark, .ink-sans, .c-display {
    overflow-wrap: anywhere;
    word-break: normal;
    hyphens: none;
  }

  /* Why `anywhere` above is now safe, having been the visible bug.
   *
   * It is a last resort: it breaks inside a word only when that word cannot
   * fit a line by itself. It was firing on every phone because the copy
   * carried a non-breaking space, which made "Wielding\u00a0Magic" a single
   * unbreakable token with no other break available — so the headline read
   * "WIELDING MAG / IC", and "WIELDING MA / GIC" at 360px.
   *
   * The hard space is now softened where copy enters the app (lib/queries.ts),
   * so the string has a real break opportunity between the two words and the
   * last resort stops being reached. Keeping `anywhere` rather than switching
   * to `normal` is deliberate: `normal` would guarantee no word is ever cut,
   * and would guarantee instead that a single word too long for the screen
   * runs off the side of it. A clipped headline is not an improvement on a
   * broken one, and Ted edits this copy himself. */

  /* ---- 2. Nothing may be wider than the phone ----------------------------
   * Their forms are 409px against a 390px viewport. Media keeps its aspect
   * ratio rather than being squashed.                                       */

  form, input, textarea, select, button,
  .c-form, .c-field, .c-formbox { max-width: 100% !important; }
  img, video, iframe, svg, canvas { max-width: 100%; height: auto; }

  /* ---- 3. Touch targets --------------------------------------------------
   * The audit found 11 to 39 controls under 44px per page. 44px is the size
   * a fingertip actually hits; below it, taps land on the wrong thing.
   * Padding rather than height, so their layout is not pushed around.       */

  a, button, [role="button"], input[type="submit"] { min-height: 44px; }
  nav a, .tk-nav a, footer a { padding-block: 10px; }

  /* ---- 4. The Tedshots carousel fits the phone ---------------------------
   * Influex already wrote this breakpoint themselves:
   *
   *   @media (max-width: 560px) { .bc-card { flex-basis: 100%; } }
   *
   * One card per view on a phone is their decision, and it is the right one.
   * It has never worked, and the reason is two lines apart in their own file.
   *
   * .ip-pin is `display: flex; flex-direction: column`, so .bc-rail is a flex
   * item and should stretch to the container's 390px. It does not, because of
   * `.bc-rail { margin: 42px auto 0 }`: a flex item with `auto` margins on the
   * cross axis is never stretched. Auto margins absorb the free space instead,
   * and the item falls back to being sized by its content. Its content is
   * .bc-track, a flex row of four cards, so the rail measures 845px inside a
   * 390px parent.
   *
   * From there `flex-basis: 100%` is 100% of 845px, which draws a 685px card,
   * and .ip-pin's `overflow: hidden` slices it. What reaches the phone is one
   * photograph wider than the screen, pushed 76px right and cut off.
   *
   * This is also why the responsive audit reported zero overflow and was right
   * to. The document really is 390px wide. The clipping happens inside a
   * container that is itself correctly sized, which no document-width check
   * can see: an element can be badly broken and perfectly contained.
   *
   * So the cross-axis margins go, which lets stretch apply, and min-width: 0
   * releases the automatic minimum on the flex chain beneath it so the track
   * and card can follow the rail down. Their own breakpoint then does exactly
   * what it says. Nothing here changes their layout, their card proportions or
   * their breakpoint; it removes what was stopping theirs from applying.
   *
   * The padding is the one number chosen here. 76px of gutter each side is a
   * 1920-canvas value; on a 390px screen it spends 39% of the width on empty
   * margin. 20px keeps their edge rhythm at a size the screen can afford. */

  .bc-rail, .bc-viewport, .bc-track, .bc-card { min-width: 0 !important; }
  .bc-rail { margin-inline: 0 !important; padding-inline: 20px !important; }
}

/* ---- Image fit, up to 1024px --------------------------------------------
 * Deliberately a wider breakpoint than the rest of this file.
 *
 * Everything above is scoped to 780px because it changes layout, and tablet at
 * 834px measured zero overflow and did not need it. But image proportions are
 * not layout: a logo squashed from 4.08:1 into a square is wrong at every size.
 * Scoping these to 780px left tablet rendering the unfixed images and matching
 * desktop's broken state exactly, which was an accident of a breakpoint chosen
 * for a different reason rather than a decision.
 *
 * 1024px stops short of desktop, where the same distortion exists in Influex's
 * live site and correcting it would change their design and break the pixel
 * proof against the frozen original. That remains theirs to call.
 */
@media (max-width: 1024px) {
  /* Images keep their own proportions inside whatever box holds them.
   *
   * The audit found images drawn at an aspect ratio their file does not have:
   * reviews/r1.png is a 4.08:1 logo rendered at 1.00:1, squashed into a square,
   * and eight more like it per page. The cause is that these images carry no
   * object-fit rule at all, so they inherit the CSS default of `fill`, which
   * stretches rather than fits. Influex uses `cover` and `contain` elsewhere in
   * their own stylesheet, so this reads as an oversight rather than a choice.
   *
   * `contain` rather than `cover` for logos and marks: a squashed logo is wrong,
   * but a cropped one is also wrong, and letterboxing is the honest option when
   * the box and the artwork disagree. Photography keeps `cover`, where filling
   * the frame is the point and a small crop is expected.
   *
   * Mobile only, deliberately. The same distortion exists in their live desktop
   * site, and correcting it there would change their design and break the
   * pixel-proof against the frozen original. That one is theirs to call. */
  img[class*="logo"], img[class*="press"], img[class*="mark"],
  .rev img, [class*="review"] img {
    object-fit: contain !important;
  }
  [class*="hero"] img, [class*="poster"] img, [class*="thumb"] img,
  [class*="card"] img, [class*="gallery"] img {
    object-fit: cover;
  }

  /* One measured overflow: heroes/cinematographer-c.jpg is drawn 10px taller
   * than its 390x250 box, so the bottom of the frame is cut. */
  [class*="hero"] img, [class*="hero"] picture { max-height: 100%; }
  table { display: block; overflow-x: auto; }

  /* ---- 2b. Fixed-width stages become fluid --------------------------------
   * The deeper cause, and the one type sizing cannot reach. Their pages are
   * built inside fixed-width stage containers chosen for the 1920 canvas:
   * /contact's .v2-stage is 720px and simply does not shrink, so the page
   * stays wider than the phone no matter how small the headline gets.
   *
   * Width is released rather than overridden with a number, so the stage takes
   * whatever the phone actually offers instead of trading one fixed size for
   * another.                                                                */

  .v2-stage, .cpage, .v2-standalone > div,
  [class*="-stage"], [class*="__stage"] {
    width: auto !important;
    max-width: 100% !important;
    /* min-width is what actually pins these open. A stage carrying a min-width
     * sized for the 1920 canvas ignores max-width entirely, which is why the
     * contact page stayed 760px wide while its headline shrank obediently. */
    min-width: 0 !important;
  }

  /* A row of tabs should wrap onto the next line rather than run off-screen. */
  .c-ptabs { flex-wrap: wrap !important; max-width: 100% !important; }
  .c-ptab  { max-width: 100% !important; }
}



/* ---- 4. The last line of defence -----------------------------------------
 * If one element still escapes at some width we have not measured, the page
 * must not become horizontally scrollable: that is the bug that reads as a
 * drifting header. Deliberately outside the media query, because a page
 * should never scroll sideways at ANY width.
 *
 * `clip`, NOT `hidden`, and the difference is the whole section.
 *
 * `overflow-x: hidden` on html/body computes the other axis to `auto` and
 * makes the body a scroll container. Every `position: sticky` on the site
 * then has a scroll container that never scrolls, so nothing sticks — at
 * every width, desktop included. That is what took out .cine-pin and
 * .finv-pin on the homepage and .ab-compass__stage on /about: measured
 * moving 1:1 with the scroll, 2000px of scroll for 2000px of travel, when
 * each is supposed to hold for a screen.
 *
 * `clip` refuses the overflow without creating a scroll container, which is
 * exactly what this rule wanted and what `hidden` cannot give it. The page
 * still cannot scroll sideways. Sticky works again.                        */
html, body { max-width: 100%; overflow-x: clip; }

/* The contact and 404 pages put `min-width: 760px` on <body> itself. Every
 * descendant inherits that floor, which is why releasing the stage containers
 * changed nothing: they were being sized inside a body already pinned open.
 * min-width beats max-width in the cascade by design, so the floor has to be
 * removed rather than out-declared.
 *
 * Only below the breakpoint. Above it the 760px floor is theirs and is exactly
 * what their layout expects. */
@media (max-width: 780px) {
  html, body, body.v2-standalone { min-width: 0 !important; }
}

/* ---- 5. Touch targets on every touch device, any screen width ------------
 * Section 3 fixed touch targets for narrow screens by testing viewport
 * width, which is a proxy: it assumes small screens are touched and large
 * ones are moused. A touchscreen laptop breaks that assumption. `pointer:
 * coarse` asks about the actual input device instead, so a touchscreen
 * laptop at 1920 gets the larger targets and a mouse-driven tablet does not.
 *
 * Desktop at 1920 measures 19 controls under 44px, 14 header nav links at
 * 79x25 and 4 tab buttons at 106x38, all failing on height only. Padding
 * those 14px taller would visibly inflate the header on the one surface
 * proven pixel-identical to the original, so this never grows a real box.
 * It grows an invisible one instead: a `::after` sized to at least 44px and
 * centred on the control, positioned absolutely so it sits outside the
 * padding/border/height box the control is actually laid out and painted
 * with. `max(44px, 100%)` means a control already 44px or larger gets an
 * overlay the same size as itself, i.e. no functional change, so this is
 * safe to point at every control on the page rather than an enumerated
 * few — it only does something where the control is genuinely undersized.
 *
 * One more variable this site has that most don't: pages are authored on a
 * fixed 1920 stage and `useStageScale` (src/App.jsx) scales that whole stage
 * down with `transform: scale()` to fit anything narrower, down to a 768px
 * floor below which it switches to true responsive layout instead. A tablet
 * at 834px is rendered at roughly 0.43 scale, so a 60px-tall button can
 * still land under 44 screen px even though its authored height is already
 * generous. The fix is their own idiom for this exact problem — nav.css:109
 * already counter-scales the mega-menu with `scale(calc(1 / var(--stage-
 * scale)))` so it renders 1:1 inside a scaled stage. Dividing the 44px
 * target by that same variable makes the overlay always resolve to a true
 * 44 screen px, at any width the stage scales to, rather than 44 of the
 * pre-scale design pixels it is actually declared in. */
@media (pointer: coarse) {
  a, button, [role="button"], input[type="submit"], input[type="button"] {
    position: relative;
  }
  a::after, button::after, [role="button"]::after,
  input[type="submit"]::after, input[type="button"]::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: max(calc(44px / var(--stage-scale, 1)), 100%);
    height: max(calc(44px / var(--stage-scale, 1)), 100%);
    transform: translate(-50%, -50%);
  }

  /* Step-indicator dots sit 8-10px apart. Growing every dot to 44px would
   * merge the whole row into one hit area and make individual dots
   * untappable, defeating the point of having separate ones. A smaller,
   * non-overlapping overlay still roughly doubles each dot's target without
   * erasing the gaps between them. Same reasoning for the inline play glyph
   * that substitutes for a letter mid-headline (about-origin.css): it sits
   * between two other characters with no room to spare. */
  .mp-carousel__dot::after, .wk-quad__dots i::after, .wk-slider__dots i::after,
  .ab-compass__dots i::after, .ao-play-o::after {
    width: max(calc(17px / var(--stage-scale, 1)), 100%);
    height: max(calc(17px / var(--stage-scale, 1)), 100%);
  }

  /* .tk-btn--bronze and .tk-btn--gold-outline (the two hero CTAs) already
   * use ::after for a shimmer sweep and set overflow: hidden to contain its
   * animation, which would also clip an overlay meant to extend past their
   * box. Both are 60px tall natively, comfortably over 44 at every width
   * this site actually ships (only dipping under it briefly around the
   * tablet-scale midpoint), so this is a known, narrow, non-visual gap
   * rather than a fix forced through by touching their animation. */
}

/* ---- 5. The sticky bar keeps its menu on a phone ---------------------------
 *
 * sticky-nav.js clones the header into a bar appended to <body>, because the
 * real header sits inside a transform:scale() stage and cannot be fixed to the
 * viewport from in there. The clone escapes the stage, and with it every rule
 * written as `.tk-stage.is-mobile .tk-menu-toggle`, which is how the hamburger
 * is shown. Outside the stage those selectors never match, so the clone falls
 * back to `.tk-menu-toggle { display: none }`.
 *
 * Measured at 390px, scrolled: the bar appears carrying the logo and nothing
 * else. No links, no menu button. On a phone, scrolling past the header leaves
 * a visitor with no navigation at all until they scroll back to the top.
 *
 * Their original does exactly the same — verified against baseline/ at the
 * same width, same result — so this is inherited rather than a port
 * regression. It is still a site you cannot navigate on a phone.
 *
 * 768px is their own MOBILE_BP, read from App.jsx rather than chosen here, so
 * the clone flips to mobile on the same width the stage does. sticky-nav.js
 * already forwards a click on the clone's button to the live one, so showing
 * it is all that was missing.                                               */
@media (max-width: 767.98px) {
  .tk-stickynav .tk-menu-toggle { display: inline-flex !important; }
  .tk-stickynav .tk-nav,
  .tk-stickynav .tk-btn { display: none !important; }
}
