/* ==========================================================================
   Sketch Gate — the "draw anything" overlay that precedes the home page.
   Injected by assets/js/sketch-gate.js on first landing of a session only.
   Never rendered server-side: crawlers and no-JS visitors get the home page.

   Phases: .is-draw (canvas, scroll locked) → .is-story (five scenes, scrolls).
   ========================================================================== */

.gate {
  --bg: var(--cream);
  --fg: var(--green);
  --ink: var(--green-900);   /* the drawn line — near-black green */
  --line: var(--cream-line);

  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  overscroll-behavior: contain;
}

.gate[hidden] { display: none; }
.gate:focus { outline: none; }

.gate.is-leaving {
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-med) var(--ease-out);
}

/* Wordmark, sitting exactly where the nav's logo sits, at every width. The gate
   hands over to the real header when it closes, so matching the header's box
   keeps the wordmark still through that swap instead of sliding in from the
   centre. This mirrors .nav-bar (4.75rem tall, items centred) inside the box
   .container gives it: capped at --container, centred, --gutter of padding.
   flex-start rather than left, so it follows the reading direction the way the
   nav does. */
.gate-mark {
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 3;
  pointer-events: none;

  display: flex;
  align-items: center;
  justify-content: flex-start;
  block-size: 4.75rem;
  max-inline-size: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* The bar spans the full width over the canvas and stays click-through so the
   visitor can draw under it, so the pointer has to be handed back on the
   wordmark alone rather than on .gate-mark. */
.gate-mark-link {
  pointer-events: auto;
  display: block;
  border-radius: var(--radius-sm);
  /* The canvas underneath sets crosshair, so the wordmark has to say clickable
     for itself. */
  cursor: pointer;
}
.gate-mark-link:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 4px;
}

/* Same 2.1rem as `.nav-logo img`, deliberately: the two are never on screen at
   once, but dismissing the gate swaps one for the other, and any difference
   reads as the wordmark jumping size on the way in. */
.gate-mark img { display: block; height: 2.1rem; width: auto; }

/* --------------------------------------------------------------- Draw stage */

.gate-stage {
  position: absolute;
  inset: 0;
  transition: opacity var(--dur-med) var(--ease-out);
}

.gate.is-story .gate-stage {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}

.gate-canvas {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  touch-action: none;          /* finger draws instead of scrolling the page */
  cursor: crosshair;
  display: block;
}

.gate-canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }

/* Prompt — never intercepts the pointer, the whole screen is drawable */
.gate-prompt {
  position: absolute;
  inset-block-start: clamp(var(--space-6), 22vh, var(--space-8));
  inset-inline: 0;
  text-align: center;
  padding-inline: var(--gutter);
  pointer-events: none;
  transition: opacity var(--dur-med) var(--ease-out);
}

.gate.has-ink .gate-prompt { opacity: 0; }

.gate-prompt-title {
  font-size: var(--text-2xl);
  font-weight: 600;
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  margin: 0;
  /* Muted, as in the Figma frame — the prompt invites, it does not shout. */
  opacity: 0.62;
}

/* ------------------------------------------------------- Cursor + trail hint */

/* Centred with auto margins, NOT `inset-inline-start: 50%` + translate(-50%).
   That pair only cancels in LTR: the inset is logical and flips to `right: 50%`
   in Arabic, while `transform` is physical and still moves left — so the two
   compounded and the hint sat a full width off to the left. */
.gate-hint {
  position: absolute;
  inset-block-start: 50%;
  inset-inline: 0;
  margin-inline: auto;
  transform: translateY(-45%);
  inline-size: min(21rem, 64vw);
  pointer-events: none;
  transition: opacity var(--dur-med) var(--ease-out);
}

.gate:not(.is-hinting) .gate-hint,
.gate.has-ink .gate-hint { opacity: 0; }

.gate-hint svg { display: block; inline-size: 100%; block-size: auto; overflow: visible; }

.gate-hint-trail {
  fill: none;
  stroke: var(--green-100);
  stroke-width: 9;
  stroke-linecap: round;
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: gate-hint-trail 3.4s var(--ease-out) infinite;
}

/* Desktop draws with the pencil; touch draws with a finger, so the hand shows
   there instead. Two triggers, not one: real touch hardware reports a coarse
   pointer, but a desktop browser in responsive/device mode does NOT — it still
   claims a fine pointer at phone width, so a capability query alone left the
   pencil showing in every mobile preview. The width arm is the same 48rem the
   rest of the gate's mobile layout switches on. */
.gate-hint-hand { display: none; }
@media (hover: none) and (pointer: coarse), (max-width: 48rem) {
  .gate-hint-pen { display: none; }
  .gate-hint-hand { display: block; }
}

.gate-hint-cursor {
  fill: var(--fg);
  offset-path: path("M232 16 C186 22 122 58 74 132");
  offset-rotate: 0deg;
  offset-distance: 0%;
  opacity: 0;
  animation: gate-hint-cursor 3.4s var(--ease-out) infinite;
}

/* Draws in, holds, fades. One pass per cycle rather than a constant loop —
   the design reads as a hand that moved once, not a spinning animation. */
@keyframes gate-hint-trail {
  0%        { stroke-dashoffset: 100; opacity: 1; }
  55%, 80%  { stroke-dashoffset: 0;   opacity: 1; }
  100%      { stroke-dashoffset: 0;   opacity: 0; }
}

@keyframes gate-hint-cursor {
  0%        { offset-distance: 0%;   opacity: 0; }
  6%        { opacity: 1; }
  55%, 80%  { offset-distance: 100%; opacity: 1; }
  100%      { offset-distance: 100%; opacity: 0; }
}

/* ---------------------------------------------------- Language toggle (En|ع) */

/* The same globe as the site nav (.nav-lang), so the language control looks and
   behaves identically inside the intro and out of it. The ring and the two
   segments are gone: one icon toggles. */
.gate-lang {
  position: absolute;
  inset-block-start: var(--space-4);
  inset-inline-end: var(--gutter);
  z-index: 4;
  display: flex;
}

.gate-lang-btn {
  appearance: none;
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  color: inherit;
  font: inherit;
  /* 44px keeps the touch target legal around a 1.35rem icon */
  min-inline-size: 44px;
  min-block-size: 44px;
  display: grid;
  place-items: center;
  cursor: pointer;
  opacity: 0.85;
  transition: opacity var(--dur-fast) var(--ease-out);
}

.gate-lang-btn svg { inline-size: 1.35rem; block-size: 1.35rem; display: block; }
.gate-lang-btn:hover { opacity: 1; }
.gate-lang-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* ------------------------------------------------------------ Draw actions */

.gate-actions {
  position: absolute;
  inset-block-end: clamp(var(--space-4), 7vh, var(--space-6));
  inset-inline: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding-inline: var(--gutter);
}

.gate-finish {
  opacity: 0;
  transform: translateY(var(--space-2));
  pointer-events: none;
  transition: opacity var(--dur-med) var(--ease-out), transform var(--dur-med) var(--ease-out);
}

.gate.has-ink .gate-finish { opacity: 1; transform: none; pointer-events: auto; }

/* Quiet, but reachable — the only way out for anyone who can't draw */
.gate-skip {
  appearance: none;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  font-size: var(--text-sm);
  opacity: 0.55;
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  transition: opacity var(--dur-fast) var(--ease-out);
}

.gate-skip:hover,
.gate-skip:focus-visible { opacity: 1; }

/* ------------------------------------------------------------------- Story */

.gate-story {
  position: absolute;
  inset: 0;
  overflow-y: auto;              /* the overlay is its own scroll container */
  overscroll-behavior: contain;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-slow) var(--ease-out), visibility var(--dur-slow);
}

.gate.is-story .gate-story { opacity: 1; visibility: visible; }
.gate-story:focus { outline: none; }

.gs {
  position: relative;
  min-block-size: 100svh;
  perspective: 1000px;           /* text rides toward the viewer through this */
}

.gs-inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: var(--space-5);
  min-block-size: 100svh;
  max-inline-size: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
  padding-block: var(--space-7) var(--space-6);
}

.gs-text {
  will-change: transform, opacity;
  transform-style: preserve-3d;
}

.gs-line {
  font-size: var(--text-xl);
  font-weight: 700;
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-tight);
  margin: 0;
  /* Half the viewport, floored and capped so every sentence holds at TWO lines
     across the desktop range. Plain 50vw shrinks exactly where more room is
     needed: at 1024 it is only 512px and the two longest sentences ran to three
     lines, while at 1920 it is 960px and they collapsed to one. The 42rem floor
     covers the narrow end, the 56rem ceiling the wide end.
     A vw/rem cap rather than a `ch` one: `ch` measures the font's zero glyph, so
     the Arabic face gave a different line length from the Latin for the same
     number. */
  max-inline-size: clamp(42rem, 50vw, 56rem);
}

/* The closing panel is static — copy, button and mark are painted as soon as it
   is on screen rather than waiting on scroll position. It is the last thing the
   intro says and the only way out of it, so it should never be invisible.
   (The two rules that used to fade it here targeted `.gs-art`, which the story
   never renders — it builds `.gs-mark-art`. They matched nothing.) */

.gs-cue {
  position: absolute;
  inset-block-end: var(--space-4);
  inset-inline: 0;
  text-align: center;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  opacity: 0.5;
  pointer-events: none;
  transition: opacity var(--dur-med) var(--ease-out);
}

.gate.is-scrolled .gs-cue { opacity: 0; }

/* The drawing itself, at any size — stroke weight stays constant */
.sk { display: block; inline-size: 100%; block-size: 100%; overflow: visible; }

.sk path {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* Scene 5: the drawing is large and passes BEHIND the O1 mark, so the mark
   crops it. Bounded on both axes so the SVG letterboxes (preserveAspectRatio)
   rather than stretching the scene out of the viewport. */
.sk-end {
  position: absolute;
  z-index: 1;
  inset-block-start: 6%;
  inset-inline-end: -6%;
  inline-size: 78%;
  block-size: min(46svh, 22rem);
}

/* The drawing in flight from the canvas to its place in scene 1 */
.gate-flyer {
  position: absolute;
  z-index: 4;
  pointer-events: none;
  transform-origin: top left;
  transition: transform 900ms var(--ease-inout);
}

/* No double image: the canvas goes the moment the clone takes over, while the
   prompt and buttons still fade out normally. */
.gate.is-flying .gate-canvas { opacity: 0; transition: none; }
.gate.is-flying .gs-shape.is-mine { opacity: 0 !important; }

/* -------------------------------------------- Field: scatter → order → lines */

/* Scenes 1–4 share this one sticky field, so it needs a phase's worth of
   scroll each. */
.gs-field { min-block-size: 420svh; }

.gs-sticky {
  position: sticky;
  inset-block-start: 0;
  block-size: 100svh;
  overflow: hidden;
  /* no perspective: scene 4 flattens the paths themselves, no 3D rotation */
}

.gs-stagebox {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}

/* Physical `left`, deliberately — this is a pixel coordinate space driven by
   JS, not text flow. `inset-inline-start` would re-anchor to the right edge in
   Arabic while the maths still counted from the left, throwing every shape off
   canvas. The composition is mirrored in JS instead (see runScroll). */
.gs-shape {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: center;
  will-change: transform, opacity;
  backface-visibility: hidden;
}

.gs-shape.is-other path { opacity: 0.75; }

/* Once edge-on the lines drift, so scene 4 is alive rather than a still.
   The drift sits on the inner SVG because the holder's transform is written
   every frame by the scroll handler — the two would fight on one element. */
.gate.is-lines .gs-shape .sk {
  animation: gs-drift 18s var(--ease-inout) infinite alternate;
}

.gate.is-lines .gs-shape:nth-child(even) .sk { animation-duration: 24s; animation-direction: alternate-reverse; }
.gate.is-lines .gs-shape:nth-child(3n) .sk { animation-duration: 30s; }

@keyframes gs-drift {
  from { transform: translateX(-5%); }
  to   { transform: translateX(5%); }
}

/* The three field texts are positioned per the design, one visible at a time.
   No max-inline-size or padding here on purpose: this block used to cap itself
   at min(34rem, 46vw), which is 471px at 1024 and a fixed 544px from 1280 up —
   so the line length stopped growing with the viewport and the longer sentences
   ran to three and four lines. Letting the block shrink-to-fit hands the job to
   .gs-line's own clamp, which is sized to hold two lines across the range.
   The 4% insets below already keep the copy off the edges. */
.gs-field .gs-text {
  position: absolute;
  opacity: 0;
  z-index: 2;
}

.gs-t1 { inset-block-start: 46%; inset-inline-start: 4%; }
.gs-t2 { inset-block-start: 46%; inset-inline-end: 4%; }
.gs-t3 { inset-block-start: 44%; inset-inline-start: 4%; }
.gs-t4 {
  inset-block-start: 16%;
  inset-inline: 0;
  margin-inline: auto;
  text-align: center;
  /* Wide enough for two lines. At 38rem the sentence broke over four. */
  max-inline-size: min(54rem, 88vw);
}

/* Split the two lines evenly rather than leaving a long line and a stub. */
.gs-t4 .gs-line { text-wrap: balance; }

.gs-t4 .gs-line { margin-inline: auto; }

/* ---------------------------------------------------------------- Scene 5 */

.gs-endtext { display: flex; flex-direction: column; gap: var(--space-4); align-items: flex-start; }

/* Static with the copy above it. A fading button under a static heading reads
   as a broken element, not as a reveal — the two are one block. */
.gs-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.btn-outline {
  border: 1px solid var(--fg);
  color: var(--fg);
  background: none;
}

.btn-outline:hover { background: var(--fg); color: var(--bg); }

.gs-mark-art { position: relative; display: flex; justify-content: center; align-items: center; }

/* Sits above the drawing — the mark is what crops it */
.gs-01 {
  position: relative;
  z-index: 2;
  inline-size: min(22rem, 70%);
  block-size: auto;
}

/* -------------------------------------------------- Narrow: centred story ---
   The side-by-side composition needs room for BOTH a half-width column of copy
   and the drawings beside it. Below ~1200px it does not have it: the copy needs
   ~672px to hold two lines, which leaves under 350px for the shapes, and they
   were landing 68px deep inside the text at 1024. So the story re-blocks the
   way it does on a phone — copy centred across the top, drawings below.

   Deliberately its own breakpoint rather than raising the 48rem one: that block
   also swaps the drawing cursor to a hand, left-aligns the wordmark and folds
   the closing panel to one column, none of which belong on a 1100px desktop
   that still has a mouse. Keep this in step with isTall() in sketch-gate.js —
   the copy centres here, and the shape tables re-block there. */
@media (max-width: 75rem) {
  .gs-field .gs-text {
    max-inline-size: none;
    inset-inline: 0;
    text-align: center;
    /* `inset-inline: 0` stretches the block from edge to edge, and the desktop
       rules that held the copy off the sides (the 4% insets, t4's 88vw cap) are
       all overridden above. Without a gutter here the longest lines run straight
       into the screen edges. --gutter is the inset the rest of the site uses, so
       the story copy lines up with the page behind it. */
    padding-inline: var(--gutter);
  }

  /* One fixed lead-in for every scene instead of 8%/8%/12% of viewport height:
     a percentage moved the copy on every device size, and on a phone it sat
     ~22px under the wordmark. The header sits 24..68, so --space-7 alone left
     only 36px under it — the copy read as part of the header. Stacked, not
     --space-8: that token is fluid and computes to 95px at 390px, i.e. LESS
     than --space-7. */
  .gs-t1, .gs-t2, .gs-t3, .gs-t4 {
    inset-block-start: calc(var(--space-7) + var(--space-5));
  }
}

/* ------------------------------------------------------------------ Mobile */

@media (max-width: 48rem) {
  .gs-inner {
    grid-template-columns: 1fr;
    gap: var(--space-4);
    padding-block: var(--space-7) var(--space-6);
  }

  /* Same --text-xl as desktop rather than stepping down to --text-lg: the token
     is already fluid, so it lands at ~22.7px here instead of desktop's 30. The
     step-down on top of that made the story copy smaller than the body text on
     the page behind it. max-inline-size still off — the block is centred and
     full-width in portrait, so a 22ch cap would re-narrow it. */
  /* Full width on a phone: there is no second column to leave room for. */
  .gs-line { font-size: var(--text-xl); max-inline-size: 100%; }

  /* This row used to carry two calls: 210 + 171 + gap overflowed 358px of
     usable width, so they wrapped and the closing panel read as a stack of two
     banners. Splitting the row with flex: 1 1 0 fixed that. There is only one
     call now, and on a single button that same rule had nothing to split
     against, so it stretched edge to edge and read as a banner by itself.
     It hugs its label and centres instead. Padding and size come from .btn:
     the tighter values here existed only to fit two buttons in the row. */
  .gs-ctas {
    inline-size: 100%;
    flex-wrap: nowrap;
    justify-content: center;
    gap: var(--space-2);
  }
  .gs-ctas .btn { white-space: nowrap; }
  .gs-endtext { align-items: center; text-align: center; }
  /* 46% measured 230..391 — the drawing ran off the right edge. Anchored to the
     mark's centre instead of floating past it. */
  .sk-end {
    inline-size: 38%;
    inset-block-start: 8%;
    /* 46% + 38% spans 46–84% of the mark. Written as a plain logical inset so
       it mirrors in Arabic — the 50%-plus-physical-translate it replaces did
       not (see .gate-hint above). */
    inset-inline-start: 46%;
  }

  /* The closing panel was a full 100svh with its content centred, so ~256px of
     empty section sat between the last line and the copy. Sizing it to its
     content instead of the viewport closes that: the panel now starts right
     under the lines, and at rest the lines stay visible above it rather than
     being pushed a whole screen away. */
  .gs-end { min-block-size: auto; }
  .gs-inner {
    min-block-size: auto;
    align-content: center;
    gap: var(--space-5);
    padding-block: var(--space-5) var(--space-6);
  }
}

/* ------------------------------------------------------------------ Motion */

@media (prefers-reduced-motion: reduce) {
  .gate-hint-trail,
  .gate-hint-cursor {
    animation: none;
    stroke-dashoffset: 0;
    offset-distance: 100%;
    opacity: 1;
  }

  .gs-end .gs-text {
    opacity: 1;
    transform: none;
  }
  .gs-ctas { opacity: 1; }
  .gate.is-lines .gs-shape .sk { animation: none; }
}

/* The gate is a full-screen takeover; a cookie bar floating over the story is
   noise, and it lands right where scene 4's lines run. It returns the moment
   the gate does. */
body:has(.gate) .consent { display: none; }
