/* ═══════════════════════════════════════════════════════════════════════════
   THE MOBILE LAYER.

   Loaded last, and every rule in here lives inside a media query. That is the
   point of the file existing at all: the desktop composition is finished and
   nobody is allowed to touch it by accident, so the phone gets its own layer
   rather than another exception buried three hundred lines into scenes.css.

   Before this file there was no mobile layer. There were seven grids
   collapsing at six different widths - 560, 640, 720, 900, 1023 - which is how
   a page ends up structurally wrong rather than merely narrow: at 700px one
   half of a section has folded and the other half has not.

   Two questions are asked here, and they are different questions:

     (max-width: 640px)   is the column narrow?   -> layout, type, media
     (hover: none)        is the finger the cursor? -> hit areas, affordances

   A tablet with a mouse gets the first and not the second. A large phone in
   landscape gets the second and not the first. Conflating them is why touch
   targets on this page were sized for a cursor that phones do not have.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────  1. THE TYPE SCALE  ──────────────────────────
   Every fluid token was a clamp whose vw term only overtakes the minimum
   somewhere above 560px, so across the entire phone range the page ran on the
   clamp floor - one fixed scale, calibrated for the narrowest case, applied to
   all of them. The visible cost was rank: --fs-lead landed at 16.8px against a
   16px body, so the sentence that carries each section read as body copy.

   Leading and tracking were the other half. Both were tuned against desktop
   headlines that occupy one or two lines. The same headline on a phone runs to
   three, and 0.94 leading that looks taut over two lines has the lines
   touching over three. Negative tracking behaves the same way: it is a
   proportion of the size, so at display sizes it tightens elegantly and at
   32px it eats the word space until "Make one video" reads as one word.
   ───────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {
  :root {
    --fs-display: clamp(2.55rem, 11.4vw, 3.5rem);
    --fs-h2:      clamp(1.9rem,  8.2vw, 2.4rem);
    --fs-h3:      1.15rem;
    --fs-lead:    1.1875rem;   /* 19px against a 16px body: a real step */

    --lh-display: 1.02;        /* was 0.94, tuned for one desktop line */
    --lh-h2:      1.1;         /* was 1.04 */

    --tr-display: -0.018em;    /* was -0.033em */
    --tr-h2:      -0.010em;    /* was -0.024em */

    /* Vertical rhythm sat at the ceiling of its clamp on a phone, so roughly a
       third of every scene was padding. The scenes are tall enough already. */
    --sec-y: clamp(2.75rem, 6vh, 4rem);
  }

  /* The micro sizes were a 9-11px floor carried over from a desktop sidebar. */
  .plane__cap { font-size: 0.75rem; }

  /* .measure is 54ch and .h2 is 18ch; on a phone the gutter decides the width
     long before either does, so both were inert. Left as they are on purpose -
     they do no harm - but the headline gets a real limit so a three-word line
     does not sit alone. */
  .h2 { max-width: none; }
}

@media (max-width: 640px) {
  .ctx-panels .scene       { padding-block: clamp(2.75rem, 8vh, 4rem); }
  .ctx-panels .scene--tall { padding-block: clamp(3rem, 9vh, 4.5rem); }
}


/* ────────────────────  2. MEDIA: THE BLACK CARD, AND WIDTH  ───────────────
   Two separate faults that looked like one.

   The first is not mobile at all and is fixed in scenes.css: `.media img` was
   never `.media video`, so a <video> inside a media box got no width, no
   height and no object-fit. It kept its intrinsic 608x1080 inside a 164px box
   with overflow hidden, which is why section s1 was a black rectangle on every
   phone while the desktop stage - a different element entirely - played fine.

   The second is here. Every media box carries a vw cap that was chosen for a
   two-column desktop layout, where the media sits in a column roughly half the
   page wide. On a phone the media IS the column, so `min(232px, 42vw)` leaves
   forty percent of the row empty next to a picture too small to read.
   ───────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {
  .media--frame { width: 100%; max-width: 320px; }
  .tracks       { width: 100%; max-width: 320px; }
  .phone        { width: 100%; max-width: 300px; }

  /* These all carried a desktop max-width that is wider than the phone column
     anyway; releasing them costs nothing and stops them capping early. */
  .node, .lane, .rules, .still--feeds, .reasons { max-width: none; }

  /* Eight columns of 9:16 at 390px is forty slivers. The column count itself
     is set further down, where the lattice is given its bleed - the two belong
     together and splitting them is how a comment ends up lying. */
  .cal { max-width: none; }

  /* The rule rows keep a three-column desktop grid at 390px, so the before,
     the after and the weight fight over 118px each. Stacked, each gets the
     full column and the strikethrough still reads against the replacement. */
  .rule {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.3rem;
    padding: 0.8rem 0.9rem;
  }
  .rule__w { justify-self: start; }

  /* The schedule lane: the middle column is the workflow name and it is the
     first thing to become unreadable. Two columns keep the job and the time. */
  .lane__job { grid-template-columns: 1fr auto; gap: 0.5rem 0.9rem; }
  .lane__job span:nth-child(2) { grid-column: 1 / -1; }
}

/* ─────────────────  THE HERO DECK, AND WHY IT IS NOT A GRID  ──────────────
   On the desktop the three clips are a deck: overlapping, tilted, at different
   depths, lit from the moon side. That composition is most of what makes the
   page look designed rather than assembled. Under 900px scenes.css flattened
   it into three equal columns, which at 390px means three 112px planes in a
   row - the same three pictures with every reason to look at them removed.

   A phone cannot have two columns, but it can have depth. So the deck stays a
   deck: the cards overlap, they alternate a degree and a half of tilt, and each
   carries the same shadow the desktop planes carry. What changes is how you
   move through it - a swipe rather than a scroll-driven camera, because that is
   the gesture a thumb already has.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  .deck__space {
    display: flex;
    grid-template-columns: none;
    gap: 0;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    /* bleed to both edges so the row reads as continuing past the screen,
       which is what tells a thumb it can be pushed */
    padding-inline: var(--gutter);
    margin-inline: calc(-1 * var(--gutter));
    /* room for the tilt and the shadow to fall outside the cards */
    padding-block: 1.1rem;
  }
  .deck__space::-webkit-scrollbar { display: none; }

  .plane {
    flex: 0 0 62%;
    width: 62% !important;     /* beats the width:100%!important set at 900px */
    scroll-snap-align: center;
    /* Overlap was -8% and the three clips read as one smeared object: on the
       desktop the cards are far apart in Z, so an overlap in X still leaves
       each one whole. Flat on a phone there is no depth to separate them, so
       the overlap has to go and the gap does the work the perspective used
       to. The tilt below is what is left of the deck, and it is enough. */
    margin-inline-end: 0.7rem;
    transition: transform 320ms var(--ease-out);
  }
  .plane:last-child { margin-inline-end: 0; }

  /* Alternating tilt, smallest in the middle. Not decoration for its own sake:
     it is what stops three portrait rectangles reading as a filmstrip. */
  .plane:nth-child(1) { transform: rotate(-1.6deg) translateY(2px) !important; z-index: 1; }
  .plane:nth-child(2) { transform: rotate(0.9deg)  translateY(-4px) !important; z-index: 3; }
  .plane:nth-child(3) { transform: rotate(-0.6deg) translateY(3px) !important; z-index: 2; }

  /* The card the thumb has centred lifts out of the stack. */
  .plane:focus-within,
  .plane:active { transform: rotate(0deg) translateY(-8px) !important; z-index: 4; }

  .plane__screen { box-shadow: var(--shadow); }
  .plane__cap { padding-inline: 0.15rem; }
}

/* ────────────────────  DEPTH FOR THE REST OF THE MEDIA  ───────────────────
   Same argument, one step quieter. Every scene's still is a picture lying flat
   on a black page; on the desktop the same pictures sit ON the page, because
   they carry a shadow and a hairline. Both are already defined as tokens, they
   were simply never applied below the deck.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  .media--frame,
  .media--card {
    box-shadow: var(--shadow);
    border: 1px solid var(--line-2);
  }
  .phone { box-shadow: var(--shadow); }
  .node, .lane, .rule { box-shadow: var(--shadow-s); }
}


/* ─────────────────────────  3. THE BOTTOM OF THE SCREEN  ──────────────────
   The loudest fault on the page. Three things were pinned to the bottom edge
   with no knowledge of each other: the cookie notice at z-210, the telemetry
   strip at bottom 0, and the resume toast at z-200 and bottom 22px.

   On a 844px phone the notice alone took 171px - a fifth of the screen - for
   as long as it went unanswered, which is to say for the whole first visit. It
   covered the third quiz question, so that question could not be answered. It
   covered all four footer legal links at every scroll position, which for an
   imprint link is not a layout problem. It covered the toast, whose only
   button then could not be pressed. Nothing in the flow reserved space for any
   of it: `body { padding-bottom: 44px }` was sized for the strip alone.

   The fix is boring on purpose. The notice becomes a bar at the bottom edge
   rather than a floating card, it sits above the strip instead of on it, JS
   measures its real height into --notice-h, and the body reserves exactly that
   much for exactly as long as the notice exists.
   ───────────────────────────────────────────────────────────────────────── */

/* viewport-fit=cover has been declared since the first version and
   env(safe-area-inset-*) appeared nowhere, so on any phone with a home
   indicator every bottom-fixed control sat underneath it.

   Every one of these stays inside a query. The insets resolve to 0px on a
   desktop, which is exactly what makes an unscoped rule dangerous rather than
   harmless: `padding-top: env(...)` would quietly become `padding-top: 0` and
   overwrite whatever the desktop rule had set. */
@media (max-width: 640px) {
  .tele { padding-bottom: calc(0.5rem + env(safe-area-inset-bottom, 0px)); }

  /* The bar was 68px of a 844px screen and it is opaque enough to read as a
     lid: it took a tenth of the viewport and sat on top of whatever the page
     was showing. 54px still clears a 44px tap target and gives back most of a
     line of text.

     One number, written once. Everything that hangs off the bar's lower edge -
     the sheet, the moon below - reads it from here, because a bar height that
     lives in three places is a bar height that will disagree with itself. */
  :root { --nav-h: 54px; }
  .nav {
    height: calc(var(--nav-h) + env(safe-area-inset-top, 0px));
    padding-top: env(safe-area-inset-top, 0px);
  }
  .sheet { inset: calc(var(--nav-h) + env(safe-area-inset-top, 0px)) 0 auto 0; }
}

@media (max-width: 640px) {
  .cookie {
    left: 0; right: 0;
    bottom: calc(44px + env(safe-area-inset-bottom, 0px));
    width: auto;
    transform: none;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    border-left: 0; border-right: 0; border-bottom: 0;
    padding: 0.9rem var(--gutter);
    gap: 0.55rem 0.9rem;
  }
  /* The entry and exit animations translated on X to undo a centring offset
     that no longer exists here, so they have to be restated in Y alone. */
  @starting-style { .cookie { transform: translateY(110%); opacity: 0; } }
  .cookie.is-out  { transform: translateY(110%); opacity: 0; }

  .cookie__text { flex: 1 1 100%; }
  .cookie__acts { margin-left: 0; width: 100%; }
  .cookie__acts .btn { flex: 1 1 0; }

  /* The toast has to clear the notice as well, not just the strip. */
  .toast { bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
  .has-notice .toast { bottom: calc(var(--notice-h, 0px) + 56px + env(safe-area-inset-bottom, 0px)); }

  /* Reserve the space, and only while there is something to reserve it for.
     --notice-h is written by js/signup.js from the element's measured height,
     because the notice is two lines in English and three in German and a
     hard-coded number would be wrong in one of them.

     Deliberately not applied above 640px. The desktop card is narrower and
     centred and the owner is happy with it; it does still overlap the footer
     when you scroll to the very end, and that is written down in the TODO
     rather than fixed here, because "nothing changes on desktop" is worth
     more right now than one tidied edge. */
  .has-notice body,
  .ctx-panels.has-notice body { padding-bottom: calc(var(--notice-h, 0px) + 44px + env(safe-area-inset-bottom, 0px)); }
}


/* ──────────────────────────  4. TOUCH: HIT AREAS  ─────────────────────────
   Everything below is 44px, which is the number both Apple and Google publish
   and the number below which a thumb starts hitting the neighbour. These were
   between 21px and 41px. The language switch, at 42x27, was the smallest
   control on the site and appears on every single screen.

   Scoped to (hover: none) rather than to width: a phone in landscape is wider
   than 640px and its owner still has fingers.
   ───────────────────────────────────────────────────────────────────────── */

@media (hover: none) {
  .lang__btn   { padding-block: 0.72rem; }
  .nav__burger { width: 44px; height: 44px; padding: 14px 11px; }
  .chip        { padding-block: 0.72rem; }
  .seg__btn    { padding-block: 0.68rem; }
  .cookie .btn { --btn-y: 0.72rem; }

  .foot__links { display: flex; flex-wrap: wrap; gap: 0 1.25rem; }
  .foot__links a { display: inline-block; padding-block: 0.7rem; }

  /* legal.html has no burger: it puts the wordmark, the language switch and a
     "back to the site" button in one 390px bar. Widening the language buttons
     for thumbs pushed that row over the edge and the button was clipped by the
     viewport. It gets its padding back, and the row is allowed to shrink. */
  .nav__right { gap: 0.5rem; min-width: 0; }
  .nav__right .btn--sm { padding-inline: 0.8rem; font-size: 0.8125rem; }
}

/* Below 400px it still did not fit, and worse in German: "Zurück zur Seite" is
   seven pixels wider than "Back to the site". Measured at 360px it overflowed
   by 7px in English and 14px in German. The room comes from the language
   switch, whose 42px cells were sized for a cursor. 36px keeps the full 44px
   height, which is the dimension a thumb actually misses on.

   All three values move together or the sliding pill stops lining up with the
   labels - the pill's width and its travel are the same number. */
@media (hover: none) and (max-width: 400px) {
  .lang__btn  { width: 36px; }
  .lang__pill { width: 36px; }
  .lang[data-on="de"] .lang__pill { transform: translateX(36px); }
  .nav__right .btn--sm { padding-inline: 0.65rem; }

  /* .btn--ghost had no base rule at all: its only declaration lived inside
     (hover: hover) and (pointer: fine). On a phone every secondary call to
     action was therefore bare text sitting next to a lit primary button -
     "See real output" under the hero read as a caption. The border is added
     only here, so the deliberately quiet desktop treatment is untouched. */
  .btn--ghost {
    border: 1px solid var(--line-2);
    color: var(--ink);
  }
  .btn--ghost:active { border-color: var(--accent); background: var(--surface); }

  /* Decorative chips are visually identical to the interactive quiz chips.
     A cursor never had to guess because it never got a pointer over them;
     a thumb has no such warning, so the decorative ones lose the affordance. */
  li.chip { opacity: 0.82; border-style: dashed; }
}


/* ───────────────────────────  5. THE PAW, AND OVERFLOW  ───────────────────
   The cursor paw is a 380px window positioned absolutely against its host. In
   section s10 that host sits far enough right that the window reached past the
   viewport and the whole page scrolled sideways by about thirty pixels - on
   every phone, in every scene, because a horizontal scroll is a property of
   the document and not of the section that caused it.

   It is a cursor decoration. A phone has no cursor, so the honest fix is not
   to clip it but to not build it: this also spares the phone 37KB of script
   doing hit-testing for a pointer that will never arrive.
   ───────────────────────────────────────────────────────────────────────── */

@media (hover: none), (pointer: coarse) {
  .paw, .paw--edge { display: none !important; }
  .paw-stage, .paw-host { position: static; }
}

/* There was an `overflow-x: clip` on html and body here as belt and braces. It
   is gone, and the reason is worth keeping.

   It worked, but it also narrowed the fixed backdrop layer from 420px to 390px,
   which resized the WebGL canvas after js/backdrop.js had already initialised
   it - and the canvas came back with a bright grey rectangle painted across the
   top third of the page, straight through the s1 headline. Hiding the canvas
   made the block vanish, which is how it was pinned down.

   Measured afterwards: with the paw gone, document.scrollWidth is 390 on a
   390px viewport with or without the clip. The overflow had exactly one cause
   and it is already fixed, so the second belt was buying nothing and costing a
   rendering bug. If a future element ever widens the page again, clip the
   section that does it, not the document.

   The canvas fault itself is latent and not ours: any resize after init can
   provoke it, including a device rotation. It is written down in the TODO. */


/* ─────────────────────  6. SOMETHING TO PRESS, ON A PHONE  ────────────────
   At 900px the nav drops its links into a sheet and deletes the primary call
   to action outright - and the sheet was never given one. From 900px down the
   page had no call to action in its chrome at all: the only way to reach the
   waiting list was to scroll the whole story. The sheet gets the button.
   ───────────────────────────────────────────────────────────────────────── */

/* The `display: none` base that used to sit here moved to styles/chrome.css.
   It was the ONE rule in this file not behind a media query, and this file is
   now loaded with a media attribute - an unwrapped rule would simply have
   stopped applying on desktop. */
@media (max-width: 900px) {
  .sheet__cta { display: block; margin-top: 1.1rem; }
  .sheet__cta .btn { width: 100%; }
}


/* ────────────────────────────  7. THE BACKDROP  ───────────────────────────
   The moon is one viewport-fixed decoration for the entire page. On desktop it
   sits beside a two-column composition and reads as a light source. On a phone
   the column is the whole screen, so the same moon lands on top of every
   headline in turn, in the same corner, eleven times - and the cloud band it
   belongs to swallows the s2 workflow card, which is why that card looked
   clipped when nothing was clipping it.

   It is not removed. It is made smaller and quieter and the scrim beneath it
   is deepened, so it still lights the page from the top right without
   competing with the words.

   night.css already has a 720px block that shrinks the moon and drops two of
   the three cloud banks, so the structure is right and only the amounts are
   wrong. Note what is NOT touched here: transform. js/night.js drives the
   moon's parallax, tilt and swell through transform, and a transform in the
   stylesheet would be overwritten on the first scroll frame - or worse, win
   until the first scroll frame and then jump. Position, size and opacity are
   ours; transform is the script's.
   ───────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {
  /* Erster Versuch war falsch herum: ich hatte ihn hochgezogen und gedimmt, um
     ihn aus dem Ueberschriftenband zu holen - und damit direkt hinter die
     Kopfleiste geschoben, wo er praktisch unsichtbar war.

     Richtig ist andersherum: unter die Leiste, dort wo Himmel frei ist, und mit
     seiner Groesse und Helligkeit zurueck. Er ist die Lichtquelle der ganzen
     Komposition; ein Mond, den man suchen muss, beleuchtet nichts. */
  .night__moon {
    top: calc(var(--nav-h, 54px) - 0.5vh);
    right: 2vw;
    width: 32vw;
    opacity: 0.95;
  }

  /* And the headline wins where they meet.
     On the desktop the moon and the words never touch, because the words are
     in a column half the page wide and the moon is in the other half. On one
     column, at full bleed, a moon anywhere in the top corner will cross the
     first line of some headline on some screen height - so rather than shrink
     it until it stops mattering, the type gets a shadow dark enough that it
     reads over the bright limb. Invisible against the black everywhere else. */
  .display, .h2 { text-shadow: 0 2px 20px rgba(0, 0, 0, 0.62); }

  /* The scrim is what actually buys the headlines their contrast back, and it
     costs nothing because it is already there. */
  .night__dim { background: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.52) 62%); }

  /* The near bank is the band that swallowed the s2 workflow card. Held lower
     so the card sits against sky rather than dissolving into cloud. */
  .night__bank--near { opacity: 0.72; }
}


/* ═══════════════════  8. THE PICTURE LANGUAGE, ON ONE COLUMN  ═════════════
   The desktop does not look designed because it has two columns. It looks
   designed because things are layered, lit from one direction, and not all
   aligned to the same rail. A phone cannot have the two columns. It can have
   the other three.

   What that means in practice, and what it deliberately does not mean: no
   scroll-driven camera, no fixed stage, no parallax. Every rule below is a
   static property. The frame budget stays where the last pass put it.
   ───────────────────────────────────────────────────────────────────────── */

@media (max-width: 640px) {

  /* ── the light has a direction ──────────────────────────────────────────
     On the desktop the moon sits beside the media and the shadow under each
     card falls away from it, so the whole composition is lit from one place.
     On a phone the moon is up in the corner and the media is far below it, so
     that reading is lost - the cards just float on black.

     Two hairlines put it back. The top and right edges catch the light, the
     bottom and left keep the base line colour, and the existing shadow does
     the rest. It is the cheapest possible lighting model and it is the one the
     page was already implying. */
  .media--frame,
  .media--card,
  .phone,
  .plane__screen {
    border: 1px solid var(--line-2);
    border-top-color: rgba(245, 245, 247, 0.20);
    border-right-color: rgba(245, 245, 247, 0.13);
  }

  /* ── not everything on the same rail ────────────────────────────────────
     The lattice is a pattern rather than an object: twenty-four slots standing
     for a year of posts. Boxed inside the text column it reads as a widget;
     running off the edge it reads as something that continues, which is what
     it means. Five columns rather than four because the row wants to be cut
     mid-repeat, not to end neatly at the margin.

     The arithmetic keeps the document exactly as wide as the viewport: the
     wrap already carries a gutter of padding, so width + gutter with a
     negative margin of the same gutter lands flush on the screen edge and not
     one pixel past it. */
  /* The bleed that used to be here was written for the lattice, and it was
     right for a lattice: a pattern gains from being cut mid-repeat, because
     that is what says it continues.

     It is wrong for what stands there now. A month has exactly seven columns.
     Cut one off at the screen edge and it stops being a month and becomes a
     grid of squares again, which is the exact problem the calendar replaced.
     So the calendar keeps both margins and fills the column instead. */
  .cal { gap: 5px; max-width: none; }
  .cal__day { border-radius: 5px; padding-inline: 20%; }

  /* The phone is an object standing in a scene, not a diagram in a document.
     Nudged off the text rail it stops reading as the next stacked block. */
  .still--phone { padding-inline-start: 14%; }

  /* Same for the clip in s1: it steps to the right of the rail the sentences
     sit on, which is the smallest possible version of "text left, media
     right" and reads as composition rather than as a column. */
  .still > .media--frame { margin-inline-start: auto; }
  .still > .tracks       { margin-inline-start: auto; }

  /* s3 and s6 carry .scene__in--right in the markup and nothing has ever read
     it. It is the page's own note about which scenes were composed the other
     way round, so on a phone it becomes the rhythm: those two turn to the
     right while the rest stay left, and the page stops marching. */
  /* s6 was right-aligning its chips, from back when the section had nothing in
     it but chips. It has a rejected clip anchored left now, and the chips are
     the answer to the question printed next to that clip - so they belong on
     the same side as the thing they answer. */
}
