/* ============================================================
   Numidea Labs — project sheets (scene/)
   A drawing office, not a light show: static drafting grid, hairline
   frames, dimension lines and a title block per project. Nothing moves on
   its own; hover states only. Markup is generated by
   scripts/build-scene.mjs — style the classes it emits.
   ============================================================ */
:root{
  --paper:#0A1420; --paper-2:#0E1B2B; --panel:#112235;
  --line:rgba(150,196,230,.16); --line-2:rgba(150,196,230,.30); --grid:rgba(150,196,230,.05);
  --ink:#E8F0F7; --muted:#A3B6C6; --faint:#8DA2B4;
  --gold:#E6B450; --teal:#46D5C3; --violet:#B9A6FF;
  --display:'Cinzel','Cinzel Fallback',Georgia,serif;
  --body:'Geist','Geist Fallback',system-ui,sans-serif;
  --mono:'Geist Mono','Geist Mono Fallback',ui-monospace,monospace;
  --ar:'IBM Plex Sans Arabic','IBM Plex Sans Arabic Fallback',system-ui,sans-serif;
  --r:10px; --gut:clamp(16px,4vw,48px); --max:1240px;
  /* the sticky .hud: 14px padding ×2, the 38px language group, 1px rule */
  --hud-h:67px;   /* header height; the crumb wraps below 320px (see the media query) */
}
/* Arabic never goes through the Latin faces (as on the main site). Geist and
   Geist Mono have no Arabic glyphs, so everything set in var(--body) or
   var(--mono) (skip link, visit and contact buttons, phone captions, the
   back link, the ع button) fell back to a system face. In Arabic the body
   stack is the Arabic one, and Plex Arabic follows Geist Mono so Latin and
   digits keep the mono face. A client voice given in Arabic gets the same on
   a French or English page. */
html[dir="rtl"],.voice[lang="ar"]{
  --body:var(--ar);
  --mono:'Geist Mono','IBM Plex Sans Arabic','IBM Plex Sans Arabic Fallback','Geist Mono Fallback',ui-monospace,monospace}
*,*::before,*::after{box-sizing:border-box}
/* anchor jumps and focus scrolling stop below the sticky header, so Shift+Tab
   never parks a focused link under it */
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;scroll-padding-top:calc(var(--hud-h) + 16px)}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{margin:0;background:var(--paper);color:var(--ink);font:400 16px/1.6 var(--body);
  -webkit-font-smoothing:antialiased;overflow-x:hidden}
/* drafting paper: fine 24px grid under a 120px major grid, fixed to the
   viewport. On its own fixed layer, not background-attachment:fixed: that
   made Chrome repaint and re-raster the whole viewport on every scroll frame
   (traced at 1280, ten wheel scrolls: raster 7.2s, now 0.13s) (r3/a) */
body::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-image:
    linear-gradient(var(--grid) 1px,transparent 1px),linear-gradient(90deg,var(--grid) 1px,transparent 1px),
    linear-gradient(rgba(150,196,230,.08) 1px,transparent 1px),linear-gradient(90deg,rgba(150,196,230,.08) 1px,transparent 1px);
  background-size:24px 24px,24px 24px,120px 120px,120px 120px}
img{display:block;max-width:100%;height:auto}
a{color:inherit}
h1,h2,h3,h4,p,ol,ul,dl,dd,figure{margin:0}
ol,ul{padding:0;list-style:none}
:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
/* parked above the page, not at left:-9999px: in RTL that offset lies in the
   scrollable direction and made the page 11 000px wide (and blank). It shows
   8px down so the focus ring around it stays inside the viewport. */
.skip{position:absolute;top:8px;inset-inline-start:8px;z-index:20;background:var(--gold);color:#0A1420;padding:8px 14px;border-radius:6px;
  font:600 14px var(--body);transform:translateY(-200%);white-space:nowrap}
.skip:focus{transform:none}

/* ---- header ---- */
.hud{position:sticky;top:0;z-index:10;display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:14px var(--gut);background:color-mix(in srgb,var(--paper) 88%,transparent);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border-bottom:1px solid var(--line)}
.bc{min-width:0}
.bc ol{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.bc li{display:flex;align-items:center;gap:10px;font:500 12px/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.bc li+li::before{content:"/";color:var(--faint)}
.hud-logo{font:700 14px/1 var(--display);letter-spacing:.12em;text-decoration:none;color:var(--ink)}
.hud-logo .d{color:var(--gold)}
/* flex:none: as a flex item with overflow:hidden it could shrink to nothing,
   and at 320-360px it clipped the ع button off */
.lang{display:flex;flex:none;border:1px solid var(--line-2);border-radius:8px;overflow:hidden}
.lang button{min-width:40px;min-height:36px;background:transparent;border:0;color:var(--muted);font:500 12px var(--mono);cursor:pointer}
.lang button[aria-pressed="true"]{background:var(--ink);color:var(--paper)}
.lang button:hover{color:var(--ink)}
.lang button[aria-pressed="true"]:hover{color:var(--paper)}
/* .lang clips its overflow, so an outside ring would be cut to stray bars:
   the ring is drawn inside, in the paper colour on the pressed (light) button */
.lang button:focus-visible{outline-offset:-3px}
.lang button[aria-pressed="true"]:focus-visible{outline-color:var(--paper)}

main{max-width:calc(var(--max) + 2 * var(--gut));margin:0 auto;padding:0 var(--gut)}
main:focus{outline:none}

/* ---- intro ---- */
.intro{padding:clamp(56px,9vw,120px) 0 clamp(40px,6vw,72px)}
.kicker{font:500 11px/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--gold);margin-bottom:20px}
.intro h1{font:700 clamp(34px,5.4vw,68px)/1.05 var(--display);letter-spacing:.01em;max-width:14em}
.intro h1 em{font-style:normal;color:var(--gold)}
html[dir="rtl"] .intro h1{font-family:var(--ar);font-weight:700;line-height:1.25}
.lead{margin-top:24px;max-width:40em;font-size:clamp(17px,1.6vw,19px);color:var(--muted)}
.index{margin-top:clamp(32px,4vw,48px)}
.index ol{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:8px}
.index a{display:flex;align-items:center;gap:12px;min-height:52px;padding:10px 16px;border:1px solid var(--line-2);
  border-radius:var(--r);text-decoration:none;background:var(--paper-2);transition:border-color .2s,background-color .2s}
.index a:hover{border-color:var(--gold);background:var(--panel)}
.ix-n{font:500 12px var(--mono);color:var(--gold);letter-spacing:.08em}
.ix-name{font-weight:600}

/* ---- a sheet ---- */
.sheet{position:relative;margin:0 0 clamp(56px,7vw,96px);padding:clamp(20px,3vw,40px);
  border:1px solid var(--line-2);border-radius:4px;background:color-mix(in srgb,var(--paper-2) 82%,transparent)}
/* registration ticks at the corners, like a plotted sheet */
.tick{position:absolute;width:14px;height:14px;border-color:var(--gold);border-style:solid;border-width:0}
.tick.tl{top:-1px;left:-1px;border-top-width:2px;border-left-width:2px}
.tick.tr{top:-1px;right:-1px;border-top-width:2px;border-right-width:2px}
.tick.bl{bottom:-1px;left:-1px;border-bottom-width:2px;border-left-width:2px}
.tick.br{bottom:-1px;right:-1px;border-bottom-width:2px;border-right-width:2px}

.sh-head{display:flex;flex-wrap:wrap;align-items:center;gap:12px 16px;padding-bottom:clamp(16px,2vw,24px);
  margin-bottom:clamp(20px,2.6vw,32px);border-bottom:1px solid var(--line)}
.sh-no{font:500 12px/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--gold)}
.sh-head h2{font:700 clamp(26px,3.2vw,40px)/1.1 var(--display);letter-spacing:.01em}
.chip{font:500 11px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;padding:7px 10px;border-radius:999px;border:1px solid}
.chip.is-live{color:var(--teal);border-color:color-mix(in srgb,var(--teal) 55%,transparent)}
.chip.is-concept{color:var(--gold);border-color:color-mix(in srgb,var(--gold) 55%,transparent)}
.chip.is-product{color:var(--violet);border-color:color-mix(in srgb,var(--violet) 55%,transparent)}
.visit{margin-inline-start:auto;display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:0 18px;
  border-radius:8px;border:1px solid var(--line-2);text-decoration:none;font:500 14px var(--body);transition:border-color .2s,background-color .2s}
.visit:hover{border-color:var(--gold);background:var(--panel)}

/* every grid gets an explicit minmax(0,1fr) column: an implicit (auto)
   column grew to the nowrap browser-bar URL and pushed the sheet 17-57px past
   the viewport at 320-376px */
.sh-body{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(20px,3vw,40px)}
@media (min-width:1000px){.sh-body{grid-template-columns:minmax(0,4fr) minmax(0,8fr);align-items:start}}
.sh-sum{font-size:17px;line-height:1.6;color:var(--ink)}
.tblock{margin:24px 0;border:1px solid var(--line-2);border-radius:6px}
.tblock div{display:grid;grid-template-columns:minmax(96px,34%) minmax(0,1fr);gap:12px;padding:10px 14px}
.tblock div+div{border-top:1px solid var(--line)}
.tblock dt{font:500 11px/1.6 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--faint)}
.tblock dd{font-size:14px;color:var(--ink)}
.sh-h{font:500 11px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--gold);margin-bottom:16px}
.deliv{display:grid;gap:8px}
.deliv li{position:relative;padding-inline-start:22px;font-size:15px;color:var(--ink)}
.deliv li::before{content:"";position:absolute;inset-inline-start:2px;top:.62em;width:9px;height:9px;border:1.5px solid var(--teal);transform:rotate(45deg)}

/* framed captures */
.frame,.phone{display:block;border:1px solid var(--line-2);background:var(--paper);overflow:hidden;cursor:zoom-in}
.frame img,.phone img{width:100%;transition:transform .4s ease}
.zoom:hover img{transform:scale(1.015)}
.sh-main{position:relative;padding:0 0 30px;margin:0}
.sh-main .chrome{display:flex;align-items:center;gap:6px;height:30px;padding:0 12px;border:1px solid var(--line-2);border-bottom:0;
  border-radius:8px 8px 0 0;background:var(--panel)}
.chrome i{flex:none;width:8px;height:8px;border-radius:50%;background:var(--line-2)}
.chrome span{min-width:0;margin-inline-start:10px;font:400 12px var(--mono);color:var(--muted);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.sh-main .frame{border-radius:0 0 8px 8px}
/* dimension lines: width under the plate, height beside it */
.dims{position:absolute;inset:30px 0 0;pointer-events:none}
.dim-w{position:absolute;left:0;right:0;bottom:0;height:14px;display:grid;place-items:center;
  font:500 11px var(--mono);letter-spacing:.1em;color:var(--muted)}
.dim-w::before{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:var(--line-2)}
.dim-w::after{content:"";position:absolute;inset:0;border-inline:1px solid var(--line-2)}
.dim-w{background:linear-gradient(var(--paper-2),var(--paper-2)) center/72px 100% no-repeat}
.dim-h{display:none}

.sh-block{margin-top:clamp(28px,3.6vw,48px)}
.pages{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(12px,1.6vw,20px)}
@media (min-width:700px){.pages{grid-template-columns:repeat(3,minmax(0,1fr))}}
.pg .frame{border-radius:6px}
.pg figcaption{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:4px 12px;margin-top:10px}
.pg b{font-weight:600;font-size:15px}
.pg code,.ph figcaption,.faces,.swatches code{font:400 12px var(--mono);color:var(--muted)}

.sh-pair{display:grid;grid-template-columns:minmax(0,1fr);gap:0 clamp(20px,3vw,40px)}
@media (min-width:1000px){.sh-pair{grid-template-columns:minmax(0,5fr) minmax(0,7fr)}}
.phones{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(12px,2vw,24px);max-width:440px}
/* the bezel's hairline is a shadow, not an outline: an outline here has the
   same specificity as :focus-visible and came later, so it replaced the ring */
.phone{border-radius:20px;border-width:6px;border-color:var(--panel);box-shadow:0 0 0 1px var(--line-2)}
.ph figcaption{margin-top:10px;text-align:center}

.system{display:grid;gap:24px;padding:clamp(16px,2vw,24px);border:1px solid var(--line-2);border-radius:var(--r);background:var(--paper)}
.system h4{font:500 11px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--faint);margin-bottom:12px}
.swatches{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:10px}
.swatches li{display:grid;gap:4px}
.swatches i{display:block;height:56px;border-radius:6px;background:var(--c);border:1px solid var(--line-2)}
.swatches b{font-size:13px;font-weight:600}
.faces{display:flex;flex-wrap:wrap;gap:8px}
.faces li{padding:8px 12px;border:1px solid var(--line-2);border-radius:6px;font-size:14px;color:var(--ink)}

/* optional client material */
.ba{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;margin-bottom:24px}
@media (min-width:700px){.ba{grid-template-columns:repeat(2,minmax(0,1fr))}}
.ba>div{position:relative}
.ba-tag{position:absolute;top:10px;inset-inline-start:10px;z-index:1;font:500 11px var(--mono);letter-spacing:.12em;text-transform:uppercase;
  padding:6px 9px;border-radius:999px;background:var(--paper);border:1px solid var(--line-2);color:var(--muted)}
.ba-tag.is-after{color:var(--teal);border-color:color-mix(in srgb,var(--teal) 55%,transparent)}
.ba figcaption{grid-column:1/-1;font:400 12px var(--mono);color:var(--muted);text-transform:capitalize}
.assets{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}
.assets a{display:grid;place-items:center;aspect-ratio:4/3;padding:16px;border:1px solid var(--line-2);border-radius:var(--r);background:#fff;cursor:zoom-in}
.assets img{max-height:100%;object-fit:contain}
.assets span{display:block;margin-top:8px;font:400 12px var(--mono);color:var(--muted);text-transform:capitalize}

/* ===== r3/b: what the work gives the client ===== */
/* Under each sheet's title block: the client's context in one sentence (a
   framed note, like the spec table), then numbered rows, each a thing a
   visitor can do on the live site today with the page that shows it
   (scripts/scene-data.mjs `gains`). From 1000px the note and the rows share
   the title block's 4/8 split; the page path sits at the row's end from
   700px and under the sentence below. Nothing moves. */
.gv-body{display:grid;grid-template-columns:minmax(0,1fr);gap:20px}
@media (min-width:1000px){.gv-body{grid-template-columns:minmax(0,4fr) minmax(0,8fr);gap:clamp(20px,3vw,40px);align-items:start}}
.gv-ctx{padding:14px 16px;border:1px solid var(--line-2);border-radius:6px;background:var(--paper);font-size:15px;line-height:1.6;color:var(--ink)}
.gv-ctx b{display:block;margin-bottom:6px;font:500 11px/1.6 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--faint)}
.gv-list{border-top:1px solid var(--line)}
.gv-list li{display:grid;grid-template-columns:auto minmax(0,1fr);gap:4px 16px;padding:14px 0;border-bottom:1px solid var(--line)}
.gv-n{grid-row:span 2;font:500 12px/25px var(--mono);letter-spacing:.08em;color:var(--gold)}
.gv-list p{font-size:15px;line-height:25px;color:var(--ink)}
.gv-list code{justify-self:start;max-width:100%;font:400 12px/1.6 var(--mono);color:var(--muted);overflow-wrap:anywhere}
@media (min-width:700px){
  .gv-list li{grid-template-columns:auto minmax(0,1fr) auto;align-items:baseline}
  .gv-n{grid-row:auto}
  .gv-list code{justify-self:end;max-width:16em;text-align:end}
}
html[dir="rtl"] .gv-ctx b{font-family:var(--ar);font-size:13px;font-weight:600;letter-spacing:0;text-transform:none}
html[dir="rtl"] .gv-n{letter-spacing:0}

/* ---- closing ---- */
.outro{display:flex;flex-wrap:wrap;align-items:center;gap:16px 24px;padding:clamp(40px,6vw,72px) 0 clamp(56px,8vw,96px);border-top:1px solid var(--line)}
.outro p{font:700 clamp(22px,2.6vw,30px)/1.2 var(--display);flex-basis:100%}
html[dir="rtl"] .outro p{font-family:var(--ar)}
.cta{display:inline-flex;align-items:center;min-height:48px;padding:0 22px;border-radius:8px;background:var(--gold);color:#0A1420;
  font:600 15px var(--body);text-decoration:none}
.cta:hover{filter:brightness(1.08)}
.back{font:500 13px var(--mono);color:var(--muted);text-decoration:none}
.back:hover{color:var(--ink)}

/* ---- viewer ---- */
.viewer{max-width:min(96vw,1600px);max-height:94vh;padding:0;border:1px solid var(--line-2);border-radius:8px;background:var(--paper);color:var(--ink);overflow:auto}
.viewer::backdrop{background:rgba(4,9,15,.86)}
.viewer img{width:100%;cursor:zoom-out}
.viewer.is-tall{max-width:min(92vw,460px)}
.viewer form{position:sticky;top:0;z-index:1;height:0;display:flex;justify-content:flex-end}
.viewer-x{margin:8px;width:40px;height:40px;border-radius:50%;border:1px solid var(--line-2);background:var(--paper);color:var(--ink);font-size:22px;line-height:1;cursor:pointer}

@media (prefers-reduced-motion:reduce){.frame img,.phone img{transition:none}.zoom:hover img{transform:none}}
@media (max-width:600px){
  .sheet{padding:16px;border-radius:2px}
  .visit{margin-inline-start:0;width:100%;justify-content:center}
  .tblock div{grid-template-columns:minmax(0,1fr);gap:2px}
}
@media print{.hud,.viewer,.skip,body::before{display:none}body{background:#fff;color:#000}}
/* Forced colours (Windows contrast themes) replace backgrounds with Canvas:
   the pressed language would look like the others, the contact button would
   lose its shape and the palette swatches (content, not decoration) their
   colour. */
@media (forced-colors:active){
  .lang button[aria-pressed="true"],.lang button[aria-pressed="true"]:hover{forced-color-adjust:none;background:Highlight;color:HighlightText}
  .lang button[aria-pressed="true"]:focus-visible{outline-color:HighlightText}
  .cta,.skip{border:1px solid ButtonText}
  .swatches i{forced-color-adjust:none}
}

/* ---- Arabic ----
   The mono labels are tracked out (.12–.18em); letter-spacing pulls Arabic
   letters apart and breaks their joins, so in RTL they take the Arabic face
   with no tracking. Measurements stay LTR ("1440 px", not "px 1440"). */
html[dir="rtl"] :is(.kicker,.sh-no,.chip,.sh-h,.tblock dt,.system h4,.bc li,.ba-tag,.ix-n){
  font-family:var(--ar);letter-spacing:0;text-transform:none}
html[dir="rtl"] .sh-h,html[dir="rtl"] .kicker{font-size:13px;font-weight:600}
.dim-w,.chrome span,code{direction:ltr;unicode-bidi:isolate}

/* client voices (scripts/voices-data.mjs), in the language they were given */
.voice{margin:0 0 16px;padding:20px 22px;border:1px solid var(--line-2);background:var(--panel);max-width:720px}
.voice blockquote{margin:0;font-size:17px;line-height:1.6;color:var(--ink)}
.voice figcaption{margin-top:12px;font:500 12px/1.4 var(--mono);letter-spacing:.06em;color:var(--muted)}
.voice[lang="ar"]{font-family:var(--ar)}
html[dir="rtl"] .voice figcaption,.voice[lang="ar"] figcaption{letter-spacing:0}
.voice figcaption b{color:var(--ink)}
/* forward arrows point the reading way: mirrored in Arabic */
html[dir="rtl"] .visit .arr{display:inline-block;transform:scaleX(-1)}
/* Below 320px the crumb wraps and the header grows (79px at 280-300, 93px at
   260): reserve that height, so focus is never scrolled under it. */
@media (max-width:319px){:root{--hud-h:96px}}
/* Arabic inside a French or English page (the ع language button) is set in
   the Arabic face, as on the home page, not a system fallback. */
html[dir="ltr"] [lang="ar"]{font-family:var(--ar);letter-spacing:0}

/* ===== r3/a: mobile audit ===== */
/* Safe-area insets. The page asks for viewport-fit=cover (it paints under
   the notch) but nothing was inset: in landscape on a notched phone, with
   ~47px insets a side, the wordmark, the language switch and the sheets'
   text ran under the notch (emulated at 844x390: the ع button at x=35, the
   wordmark to x=810 of 844). */
@supports (padding:max(0px)){
  .hud,main{padding-left:max(var(--gut),env(safe-area-inset-left));padding-right:max(var(--gut),env(safe-area-inset-right))}
}
/* The capture viewer: 94vh is the LARGE viewport on iOS, taller than what
   shows while the toolbars are out, so the foot of a tall capture sat under
   them. 94dvh is what is on screen. */
@supports (height:1dvh){.viewer{max-height:94dvh}}
