/* ==========================================================================
   Battuta landing page - stylesheet
   Standalone marketing surface. No build step, no external requests, and no
   relationship to any other surface in this repository (owner ruling LP-R3).
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Fonts - self-hosted, replacing the export's Google Fonts <link>.
   IBM Plex Sans Arabic v1.101, SIL OFL 1.1. See fonts/OFL.txt.
   font-display:swap matches the export's "&display=swap".
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/IBMPlexSansArabic-Regular.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('fonts/IBMPlexSansArabic-SemiBold.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('fonts/IBMPlexSansArabic-Bold.woff2') format('woff2');
}

/* --------------------------------------------------------------------------
   2. Document styles - lifted verbatim from the export's <helmet><style>.
   Unchanged: same selectors, same declarations, same breakpoints.
   -------------------------------------------------------------------------- */
html{scroll-behavior:smooth}
body{margin:0;background:#F6F4EF;color:#1B2421;font-family:'IBM Plex Sans Arabic','Segoe UI',system-ui,sans-serif;-webkit-font-smoothing:antialiased}
a{color:#0E6F66}a:hover{color:#DF6448}
::selection{background:rgba(217,160,47,.35)}
summary{list-style:none;cursor:pointer}summary::-webkit-details-marker{display:none}
details[open] [data-chev]{transform:rotate(180deg)}
details[open] summary [data-q]{color:#0E6F66}
@media (max-width:1024px){
/* The route paints in DOM order and every card carries z-index:1, so on a
   single-column layout the line runs BEHIND opaque card backgrounds and is
   invisible for most of the page. Measured at 375px, the widest free margin
   beside opaque content is 12px in the hero and 19px in features, so keeping
   the line in the gutter is not an option here the way it is on desktop.
   Lifting it above the cards (but below the z-60 nav) is what makes it a route
   again. Text stays knocked out of the mask either way, so it still reads as
   passing behind the words. */
[data-route-svg]{z-index:5}
/* Lifted above the cards, the line also crosses their artwork, which the mask
   cannot help with: it knocks out TEXT, and a card background is not text. At
   full strength that competes with the content it is drawn over. Toned to .6 so
   it reads as an underlay on the cards while staying legible on the cream page
   background between them.
   The PINS keep full strength deliberately. They mark where the route starts
   and ends, they sit on open background rather than over cards, so there is
   nothing for them to compete with. (This comment used to say «the pins AND the
   plane»; the plane is now hidden on mobile by the rule below, so it no longer
   does.) */
[data-route-line]{opacity:.6}
/* THE ARROWHEAD IS BACK. It was hidden here on 2026-08-31 («the arrow remove it
   from the mobile version») and restored the next day on the owner's own
   screenshots («return the arrow head of the line»). Recorded rather than
   quietly reverted: the first removal was a real instruction and the reversal
   is a real one, and a future reader finding no trace of either would assume
   the hide was an accident. */

/* The route START belongs BEHIND the phone, not drawn across its screen.
   Lifting the route to z-index:5 above the cards also lifted it above the hero
   mockup, and `data-route-pt="start"` sits INSIDE that phone at top:24%, so the
   pin and the first leg landed on the app screenshot. (Owner, from a device
   screenshot: «the begiining sohuld be behind the image phone not above it».)

   ⚠ IT HAS TO GO ON `[data-hero]`, NOT ON THE PHONE. The obvious fix is a
   z-index on the phone itself, and it does NOTHING — measured, not assumed.
   `[data-hero]` carries an inline `z-index:1`, and a positioned element with a
   z-index CREATES A STACKING CONTEXT: every z-index inside it is ranked only
   against its siblings within that context, and the context as a whole is what
   competes with the route's 5. So a phone at z-index:6 is «6 among the hero's
   children», still inside a box that loses to the route.

   Raising the context is therefore the fix, and it is also the right one for
   the look: the whole hero, copy included, sits above the route, so the line is
   hidden for that region and emerges below the phone. `!important` is required
   because the 1 it overrides is an inline style. */
[data-hero]{z-index:6!important}

/* THE DARK SHOWCASE PANEL OUTRANKS THE ROUTE TOO, for the same reason the hero
   does and a stronger one: it is the highest-contrast block on the page, its
   copy is light-on-dark, and a coral dashed line drawn across «جولة سريعة داخل
   بطوطة» and the numbered steps competes directly with the words. Legibility
   beats decoration. (Owner, from a device screenshot: «Make the dashed line
   behind this section so user can read».)

   The line disappears for the height of the panel and re-emerges below it,
   which is the same behaviour the hero already has, so it reads as the route
   passing behind the section rather than as a broken line. */
/* `!important` for the same reason [data-hero] needs it: the section carries an
   inline z-index, and an inline style beats a stylesheet rule without it. The
   first attempt without it computed to 1 and changed nothing. */
[data-asec="showcase"]{position:relative;z-index:6!important}

/* Thinner on phones. 3px is tuned for a 1440px canvas where the line runs in
   the gutters; in a 375px column crossing content it reads heavy. */
[data-route-line]{stroke-width:2.2}

/* PERSONAS: two-up and compact. The cards are a fixed `width:198px` in a
   wrapping flex row, and 198 + 198 + a 20px gap is 416 against a 375px
   viewport, so exactly one fits per row and four of them cost over a thousand
   pixels of scroll for a section that is not the point of the page. Halving the
   rows is the whole fix; nothing is removed and no copy changes.
   The avatar is targeted structurally because these cards carry inline styles
   and this directory has no build step to add classes with. */
/* `calc(50% - 10px)` is the mathematically exact width for two columns with a
   20px gap, and it WRAPPED: the cards rounded up to 159px each, and
   159+159+20 = 338 against a 335px container. Exact is the wrong target when
   sub-pixel rounding gets a vote, so this leaves 4px of slack.

   ⚠ `box-sizing:border-box` IS THE LOAD-BEARING PART, not the calc. These cards
   compute to `content-box`, so `width` sets the CONTENT box and the padding and
   border are added OUTSIDE it: a card asked for 155.5px measured 178.5px
   (155.5 + 20 padding + 3 border), and two of those plus a 20px gap is 377
   against a 335px container. Two successive width tweaks changed nothing
   because the width was never the problem. Found by reading the computed box
   rather than by arithmetic on what the width «should» have been. */
[data-persona-off]{box-sizing:border-box!important;width:calc(50% - 12px)!important;padding:16px 10px!important;border-radius:20px!important}
[data-persona-off] > div:first-child > div:first-child{width:52px!important;height:52px!important;font-size:21px!important}
[data-sticker]{display:none!important}
[data-navlinks]{display:none!important}
[data-hero]{grid-template-columns:1fr!important;gap:44px!important}
[data-hero-copy]{text-align:center!important;align-items:center!important}
[data-feat]{grid-template-columns:repeat(2,1fr)!important}
[data-span3]{grid-column:span 2!important}
}
@media (max-width:700px){
[data-feat]{grid-template-columns:1fr!important}
[data-span2],[data-span3]{grid-column:auto!important}
[data-persona-off]{margin-top:0!important}
}

/* --------------------------------------------------------------------------
   3. Components - inline styles that repeated across the export, lifted to
   classes verbatim. Declarations are byte-identical to the inline strings
   they replaced, so computed appearance is unchanged.
   -------------------------------------------------------------------------- */
.nav-cta{margin-inline-start:auto;background:#0E6F66;color:#F6F4EF;text-decoration:none;font-weight:600;font-size:15px;padding:10px 22px;border-radius:999px;white-space:nowrap;flex-shrink:0;transition:transform .25s,background .25s}
.nav-link{color:#1B2421;font-weight:600;font-size:15px;text-decoration:none;white-space:nowrap;flex-shrink:0}
.store-btn{display:flex;align-items:center;gap:12px;background:#1B2421;color:#F6F4EF;border-radius:18px;padding:12px 22px;text-decoration:none;box-shadow:0 6px 0 rgba(27,36,33,.16);transition:transform .25s,box-shadow .25s}
.store-btn-dark{display:flex;align-items:center;gap:12px;background:#1B2421;color:#F6F4EF;border-radius:18px;padding:13px 24px;text-decoration:none;box-shadow:0 6px 0 rgba(0,0,0,.2);transition:transform .25s,box-shadow .25s}
.footer-link{color:rgba(246,244,239,.78);text-decoration:none;font-size:14.5px;font-weight:600;transition:color .25s}
.faq-item{background:#FFFFFF;border:1.5px solid rgba(27,36,33,.1);border-radius:20px;overflow:hidden}
.faq-q{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px 24px;font-weight:600;font-size:17px}
.faq-a{margin:0;padding:0 24px 22px;color:rgba(27,36,33,.66);line-height:1.95;font-size:15px}
.phone{width:250px;background:#12201C;border-radius:42px;padding:10px;box-shadow:0 30px 60px rgba(5,30,27,.5)}
.phone-screen{background:#F6F4EF;border-radius:34px;overflow:hidden;position:relative;aspect-ratio:9/18}
.feat-card{background:#FFFFFF;border:1.5px solid rgba(27,36,33,.08);border-radius:28px;padding:26px;display:flex;flex-direction:column;gap:12px;transition:transform .3s,box-shadow .3s}

/* Section eyebrow (kicker) above an <h2>. Unlike the rules above this is not
   lifted verbatim from the export - the export had two hand-rolled copies at a
   fixed 13/13.5px that did not scale, so beside a clamp()ed h2 they shrank to
   an orphaned line at desktop widths. One spec now, shared: the size clamp
   tracks the headline, and --on-dark only swaps the two colours so the pair
   can never drift in size again. Layout spacing stays at the call site - the
   features section needs a margin, the showcase section gets it from flex gap. */
.eyebrow{display:inline-block;font-size:clamp(14px,1.4vw,17px);font-weight:700;color:#0E6F66;border:2px dashed rgba(14,111,102,.45);padding:6px 15px;border-radius:6px;transform:rotate(-3deg)}
.eyebrow--on-dark{color:rgba(246,244,239,.92);border-color:rgba(246,244,239,.5)}

/* --------------------------------------------------------------------------
   4. Hover states (owner ruling LP-R1).
   The export carried these as hover-style attributes, which its
   runtime never implemented - see FINDINGS.md F-LP-1. The declarations below
   are those attribute values verbatim, restored as real :hover rules so the
   approved design's hover behaviour actually fires. Each element already
   declared a matching `transition:`, which is what these animate.
   -------------------------------------------------------------------------- */
.nav-cta:hover{background:#0A4A43;transform:translateY(-2px)}
.store-btn:hover{transform:translateY(-3px);box-shadow:0 10px 0 rgba(27,36,33,.2)}
.store-btn-dark:hover{transform:translateY(-3px);box-shadow:0 10px 0 rgba(0,0,0,.24)}
.footer-link:hover{color:#F6F4EF}
.card-lift:hover{transform:translateY(-5px)}
.card-lift-lg:hover{transform:translateY(-5px);box-shadow:0 22px 44px rgba(27,36,33,.12)}

/* --------------------------------------------------------------------------
   5. Final CTA background.
   The export exposed this as an editor prop `finalCta` (enum teal|coral,
   default teal); its render step turned it into an inline style object. The
   default is the rule below. To switch, swap the class on the single
   `<div class="cta-bg">` in index.html to `cta-bg--coral`.
   -------------------------------------------------------------------------- */
.cta-bg{position:absolute;inset:0;background:linear-gradient(160deg,#0C5950,#0A4A43 55%,#093F39)}
.cta-bg--coral{position:absolute;inset:0;background:#DF6448}

/* --------------------------------------------------------------------------
   6. Screenshot slots - see SLOTS.md.
   Each slot renders its designed placeholder (a tinted block plus the
   «معاينة مؤقتة» tag) until a file appears at the documented path. landing.js
   probes each path; when one resolves it sets the background and marks the
   slot `.shot-ready`, which hides the mock content and the tag. Dropping the
   file in is therefore the entire swap - no HTML or CSS edit.

   The background sizing is applied inline by landing.js rather than declared
   here, because each slot's own inline `background:` shorthand would outrank
   a rule at this level. See the note in loadShots().
   -------------------------------------------------------------------------- */
[data-shot].shot-ready > *,[data-screen-slot].shot-ready > *{display:none}

/* --------------------------------------------------------------------------
   7. Reduced motion.
   landing.js reads prefers-reduced-motion and takes its static path, which
   settles every animated element at its end state. This block is the
   no-JS-yet backstop: it suppresses the two CSS-declared transitions that
   could otherwise animate before the script runs.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html{scroll-behavior:auto}
  .nav-cta,.store-btn,.store-btn-dark,.footer-link,.feat-card,[data-chev]{transition:none}
}

/* --------------------------------------------------------------------------
   8. Narrow-viewport feature grid (audit F-AUD-LP-4, owner ruling R-AUD-LP-4).
   NOT part of the verbatim export lift in §2 - this is an added fix, kept in
   its own section so §2's "unchanged from the export" claim stays true.

   At <=700px [data-feat] collapses to a single `1fr` column, and `1fr` is
   `minmax(auto,1fr)`: the track cannot shrink below the item's content-based
   minimum. Two cards declare inner floors - «مجتمع الرحّالة» (min-width 240px
   + 220px on a wrapping flex row) and «المخطط» (260px) - which put their
   min-content at 391.6px and 312.4px against a 320px container at a 360px
   viewport. Every other card measures 118-149px. The widest therefore set a
   388.7px track inside 320px, the card overhung the viewport's left edge by
   50px, and an ancestor's `overflow-x:clip` cut it with no scrollbar: four
   runs of body copy were silently truncated.

   `min-width:0` here releases the automatic minimum so the track may shrink.
   That alone is what was missing: relaxing only the inner floors to
   `min(240px,100%)` measurably did NOTHING, because during intrinsic track
   sizing the percentage resolves against an indefinite containing block. With
   the card free to be 320px the inner floors resolve against a DEFINITE width
   and the flex row wraps as designed.

   No `!important`, unlike its neighbours above: no card declares an inline
   min-width, so there is nothing to outrank.
   -------------------------------------------------------------------------- */
@media (max-width:700px){
  [data-feat] > *{min-width:0}
}

/* --------------------------------------------------------------------------
   9. Batch-2 fixes (audit F-AUD-LP-14 / -21, owner ruling LP-R4).

   .shot-tag was the one class used in index.html with no rule behind it: ten
   copies of the same ~180-character inline style, which is exactly what §3
   exists to prevent. Declarations are the inline string verbatim.

   The tap targets are the rest: footer and nav links measured 22px tall and the
   nav CTA 42px, against a 44px minimum, at every width including touch. Padding
   is added rather than font-size, so nothing reflows.
   -------------------------------------------------------------------------- */
.shot-tag{position:absolute;bottom:10px;left:50%;transform:translateX(-50%);background:rgba(27,36,33,.78);color:#F6F4EF;font-size:10.5px;font-weight:600;padding:4px 12px;border-radius:999px;z-index:3;white-space:nowrap}
.nav-link{padding:11px 9px}
.footer-link{display:inline-block;padding:11px 9px}
.nav-cta{padding:11px 22px}
.brand-link{padding:4px 0}

/* --------------------------------------------------------------------------
   10. Empty screenshot slots cost 740px of phone scroll (measured 375x812).

   The feature section runs 3004px on a 375px viewport - 3.7 screens for six
   cards - and 903px of that is screenshot slots showing nothing, because
   shots/ holds only a .gitkeep. Six «معاينة مؤقتة» pills is a third of the
   scroll spent on absent content.

   Rejected first: a 2-up grid below 700px. It saves more (1049px) and it
   wrecks the cards - 164-177px tracks wrap both title lines, break body copy
   into 2-3 word fragments, and squeeze «مجتمع الرحّالة», whose min-content is
   396px. §8 above is the record of what a too-narrow track already did here
   once. Column count was never the problem; empty boxes were.

   Scoped to the slots that are ACTUALLY empty - :not(:has(> :not(.shot-tag)))
   means "nothing inside but the placeholder pill". Four qualify: journal,
   places, badges, planner. The other six carry designed content that must
   survive - «مجتمع الرحّالة» its two mock post cards, «خريطتك الشخصية» a real
   world-map <img>, and the three phone screens their mock UI. A blanket
   [data-shot] rule would delete all of it, which is why this is not one.

   Self-reversing, so there is no rule to remember to delete (R-AUTO-5):
   loadShots() adds .shot-ready the moment a file resolves at the documented
   path, and .shot-ready fails the selector. Drop a real screenshot into
   shots/ and that slot returns to full height on phones by itself - no HTML
   edit, no CSS edit, matching §6's single-file-drop contract.

   :has() is required. Where it is unsupported the whole selector is invalid,
   the rule is dropped, and the slots render exactly as they do today.
   -------------------------------------------------------------------------- */
@media (max-width:700px){
  [data-shot]:not(.shot-ready):not(:has(> :not(.shot-tag))){display:none}
}
