/* Bebas Neue + DM Mono are now loaded via the single consolidated Google Fonts <link>
   enqueued in included/enqueue.php (handle: offart-fonts). The old render-blocking
   @import that lived here serialized the font download and delayed first paint. */

/* OFFART OS — Stage 5 "The Build" cube. Tokens from stages.css :root.
   Visible by default; JS enhances. Never overlaps the .glass-deck dock.
   Motion model: explode-in assemble → velocity+friction browse → explode-out disassemble. */

/* A11y (heading-order): the os-cards (<h3>) are force-visible by design even while
   Stage 5 is inactive, but the section's <h2 data-stage-heading>OFFART OS</h2> inherits
   the stage's visibility:hidden — so the accessibility tree saw H1(hero) → H3(card),
   skipping H2. Keeping this heading in the a11y tree (it stays visually clipped via
   .sr-only) restores a valid H1 → H2 → H3 order. */
#stage-5 [data-stage-heading]{ visibility: visible; }

#offart-os{
  --os-font-display:"Bebas Neue",var(--font-head,"Audiowide",sans-serif);
  --os-font-mono:"DM Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-family:var(--os-font-mono);
}

/* ---- HUD ---- */
.os-hud{ position:absolute; top:74px; right:28px; z-index:6; text-align:right;
  font-family:var(--os-font-mono); font-size:10px;
  letter-spacing:.16em; text-transform:uppercase; color:rgba(255,255,255,.4); }
.os-hud-pct{ font-family:var(--os-font-mono); font-size:14px; color:var(--accent,#c9a84c); }
.os-hud-bar{ width:108px; height:1px; background:rgba(255,255,255,.18); margin:7px 0 5px auto; position:relative; overflow:hidden; }
.os-hud-bar i{ position:absolute; inset:0 auto 0 0; width:0; background:var(--accent,#c9a84c); }
.os-hud-ph{ color:var(--accent,#c9a84c); opacity:.7; font-size:9px; }

/* Pillar C item 4 — page-level grid background, mirroring #stage-1::before
   for visual continuity with the hero. 1px white lines every 80px at 2%
   alpha, masked by a radial gradient so the grid fades to invisible at
   the edges. Mask center = 50% 50% (where the cube sits) vs hero's 50% 40%.
   Sits BELOW .os-scene (z:3) and all interactive layers; only paints over
   #offart-os's flat #050505 background.
   Rollback: delete this #offart-os::before block. */
#offart-os::before{
  content:"";
  position:absolute;
  inset:0;
  /* alpha history: .02 (C-4 stage-1 mirror) -> .05 (C-6 bump, too prominent
     during assemble/disassemble) -> .03 (C-7, midpoint). Rollback: .03 -> .05 or .02. */
  background-image:
    linear-gradient(rgba(255,255,255,.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.03) 1px, transparent 1px);
  background-size:80px 80px;
  mask-image:radial-gradient(ellipse at 50% 50%, black 20%, transparent 70%);
  -webkit-mask-image:radial-gradient(ellipse at 50% 50%, black 20%, transparent 70%);
  pointer-events:none;
  z-index:0;
}

/* ---- Scene + cube — smaller cube + farther perspective for elegant 3D ---- */
.os-scene{ position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  perspective:1400px; z-index:3; cursor:grab; touch-action:none; }
.os-scene:active{ cursor:grabbing; }
.os-cube{ --s:min(46vw,56vh,340px); width:var(--s); height:var(--s); position:relative;
  transform-style:preserve-3d; will-change:transform; }

/* Pillar C item 3 — rim light / ambient backlight.
   Pseudo-element behind the cube (z-index:0 vs scene's perspective layer).
   Pure CSS radial-gradient, NO filter, NO box-shadow on a 3D-transformed
   element — keeps the anti-freeze rule (line 31-32) intact.
   Sized 1.6x the cube width via the same --s formula, so mobile (240px)
   gets a 384px halo and desktop (340px) gets a 544px halo automatically.
   Fade-out on .os-resolved uses a class that render() already manages
   (line 398), so no JS change needed.
   Rollback: delete this rule + the .os-resolved sibling below. */
.os-scene::before{
  content:"";
  position:absolute;
  left:50%; top:50%;
  width:calc(min(46vw,56vh,340px) * 1.6);
  height:calc(min(46vw,56vh,340px) * 1.6);
  border-radius:50%;
  transform:translate(-50%,-50%);
  /* alpha history: .10 (C-3) -> .15 (C-3 bump). Rollback: .15 -> .10. */
  background:radial-gradient(circle, rgba(255,235,200,.15) 0%, transparent 60%);
  pointer-events:none;
  z-index:0;
  transition:opacity .4s ease;
}
#offart-os.os-resolved .os-scene::before,
#offart-os.os-failed .os-scene::before{ opacity:0; }

/* Faces: classic 6-face cube layout via CSS custom-property axis.
   JS sets --e (explode offset px) for assemble/disassemble only; browse phase keeps --e:0.
   Wall = organic dim-gallery surface with directional lighting (no grid — grid reads as UI/blueprint).
   All lighting is STATIC (no per-frame filter/blend) per anti-freeze rule. */
.os-face{ position:absolute; inset:0; overflow:hidden; backface-visibility:hidden;
  background:
    /* Soft ceiling-spot highlight, upper-left.
       History: 45% (orig) -> 55% (C-2) -> 62% (C-2 bump, user said C felt too subtle).
       Rollback: 62%->55% restores moderate; 62%->45% restores original. */
    radial-gradient(ellipse 70% 62% at 28% 12%, rgba(255,235,200,.055) 0%, transparent 55%),
    /* Deep falloff, bottom-right corner */
    radial-gradient(ellipse 75% 55% at 78% 92%, rgba(0,0,0,.55) 0%, transparent 62%),
    /* Centre wash — neutral lift over the wall.
       History: rgba(120,85,40) amber (orig) -> rgba(255,255,255) neutral (C-5, user dropped brown).
       Alpha history: .035 -> .07 -> .10 (kept the bumped intensity).
       Rollback to warm: rgba(255,255,255,.06) -> rgba(120,85,40,.10). */
    radial-gradient(ellipse 50% 40% at 50% 55%, rgba(255,255,255,.06) 0%, transparent 70%),
    /* Base wall gradient — slate, mostly neutral with subtle cool hint.
       History: #1c1612->#100b08 (warm brown, orig+C-2) -> #141414->#0a0a0a (pure
       neutral, C-5, blended into bg) -> #1a1c22->#0e1015 (C-6 cool slate, too
       blue) -> #1f2024->#14161a (C-7, less blue, +5 brightness) -> #222428->
       #17191d (C-8, another +3-4 brightness, same hue).
       Rollback chain: #1f2024->#14161a (C-7) | #1a1c22->#0e1015 (C-6) |
       #141414->#0a0a0a (C-5) | #1c1612->#100b08 (warm orig). */
    linear-gradient(170deg, #222428 0%, #17191d 100%);
  opacity:1;
  transform:
    var(--axis,none)
    translate3d(var(--fly-x,0px),var(--fly-y,0px),calc(var(--s) / 2 + var(--e,0px)))
    rotateX(var(--tilt-x,0deg))
    rotateY(var(--tilt-y,0deg))
    rotateZ(var(--tilt-z,0deg)); }
.os-f1{ --axis: rotateX(-90deg); }   /* TOP    — face 1 (contact / WE BUILD SYSTEMS) */
.os-f2{ --axis: rotateY(0deg); }     /* FRONT  — face 2 (gallery). MUST be rotateY(0deg), not `none`:
                                        per CSS spec `transform: none <fn>` is invalid syntax and the
                                        whole property is dropped, embedding this face at the cube center. */
.os-f3{ --axis: rotateY(90deg); }    /* RIGHT  — face 3 (course) */
.os-f4{ --axis: rotateY(180deg); }   /* BACK   — face 4 (faq) */
.os-f5{ --axis: rotateY(-90deg); }   /* LEFT   — face 5 (articles) */
.os-f6{ --axis: rotateX(90deg); }    /* BOTTOM — face 6 (wacky) */

/* Pillar C item 1 PROTOTYPE — wall grain texture ("fiberglass guitar back").
   Applied to .os-f2 (FRONT face — second face the user sees during BROWSE,
   highly visible) ONLY, per brief request:
     "prototype each in a single .os-face first (not all 6) to confirm
      paint cost is acceptable before scaling".
   The WebP is a 256x256 grayscale tile. mix-blend-mode:overlay blends the
   grain over the wall's existing 4-layer gradient so the directional
   lighting + falloff stay intact while gaining fine grain.
   Static — no per-frame work; the browser rasterizes the blended layer
   once per face and reuses it through the cube's rotation.

   Tile contrast history (regenerated via tools/make-wall-grain.py):
     C-1a: range 110-148, weave 148 @ 5px, ~10KB. Too close to overlay-
       neutral 128 -> grain visually disappeared after blending.
     C-10: range 60-210, weave 215 @ 6px, ~23KB. Pixels far enough from
       128 that overlay actually shows them as visible bumps on the
       dark wall (light pixels brighten, dark pixels darken = real
       dimensional roughness).

   When ready to scale: change `.os-f2::before` -> `.os-face::before`.
   Tuning knobs: opacity, background-size (smaller = denser grain).
   Rollback: delete this rule. The .webp can stay - unused = no cost.
   To restore lower contrast tile: rerun make-wall-grain.py with the
   C-1a range (110-148) noted above. */
.os-f2::before{
  content:"";
  position:absolute; inset:0;
  background:url("../textures/wall-grain.webp") repeat;
  background-size:256px 256px;
  mix-blend-mode:overlay;
  /* opacity history: 0.5 (C-1a) -> 0.65 (C-1a bump) -> 0.8 (C-8) -> 1.0
     (C-9, user: "raise to 1"). Rollback chain: 1.0 -> 0.8 -> 0.65 -> 0.5. */
  opacity:1;
  pointer-events:none;
  z-index:0;
}

/* Spot light overlay — directional fill, ABOVE wall, BELOW frame.
   Static radial-gradient, no per-frame work.
   History: .04 (orig) -> .07 (C-2) -> .10 (C-2 bump). Rollback: .10->.07->.04. */
.os-face-spot{ position:absolute; inset:0; display:block; pointer-events:none;
  background:
    radial-gradient(ellipse 85% 60% at 50% -10%, rgba(255,235,195,.10) 0%, transparent 55%),
    radial-gradient(ellipse 40% 60% at 50% 50%,  rgba(255,235,195,.10) 0%, transparent 70%); }

/* Plinth — 3D base/pedestal at the bottom of the face, like a museum dais.
   Top edge catches the spot; sides drop into shadow. */
.os-face-plinth{ position:absolute; left:6%; right:6%; bottom:4%;
  display:block; height:22%; pointer-events:none;
  /* Plinth — cool stone (matches the cool-slate wall). Top edge highlight
     below stays warm (rgba(255,230,180,.14)) since it reflects the warm spot.
     History: #1f1813->#0c0805->#100c08 (warm orig) -> #1a1c22->#0a0c10->#14161c
     (C-6) -> #1f2024->#0e0f14->#16181e (C-7) -> #222428->#111217->#191b21
     (C-8, +3-4 brightness to match the wall lift).
     Rollback chain: #1f2024->#0e0f14->#16181e (C-7) | #1a1c22->#0a0c10->#14161c
     (C-6) | #1f1813->#0c0805->#100c08 (warm orig). */
  background:
    linear-gradient(180deg, #222428 0%, #111217 65%, #191b21 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,230,180,.14),   /* top edge highlight (catches spot) */
    inset 0 -1px 0 rgba(0,0,0,.5),         /* bottom edge shadow */
    inset 1px 0 0 rgba(255,230,180,.04),
    inset -1px 0 0 rgba(0,0,0,.3),
    0 -2px 6px rgba(0,0,0,.4),             /* contact shadow under frame */
    0 8px 14px rgba(0,0,0,.4);             /* drop shadow on wall behind */ }

/* Frame — moved to upper area (38%) to leave room for plinth below.
   Multi-stop metallic gradient (sheen) + 4-sided bevel inset shadows + 3-layer cast shadow. */
.os-face-frame{ position:absolute; left:50%; top:38%; transform:translate(-50%,-50%);
  width:60%; height:50%; display:block; padding:4.5%;
  background:
    linear-gradient(135deg,
      #e6c074 0%,
      #c9a04a 22%,
      #8c6a28 50%,
      #c9a04a 78%,
      #e6c074 100%);
  box-shadow:
    /* Bevel — top/left light, bottom/right dark */
    inset 0 2px 0 rgba(255,235,180,.45),
    inset 2px 0 0 rgba(255,235,180,.18),
    inset 0 -2px 0 rgba(0,0,0,.45),
    inset -2px 0 0 rgba(0,0,0,.32),
    /* Cast shadow on wall — close+sharp + far+soft (layered for photographic feel) */
    0  4px  8px rgba(0,0,0,.70),
    0 12px 24px rgba(0,0,0,.55),
    0 28px 56px rgba(0,0,0,.30); }
.os-face-mat{ display:block; width:100%; height:100%; padding:9%;
  background:
    /* Subtle paper warmth — slightly brighter top, hint of texture via overlapping radials */
    radial-gradient(ellipse 90% 60% at 50% 0%, rgba(255,252,240,.55) 0%, transparent 50%),
    radial-gradient(ellipse 50% 30% at 30% 80%, rgba(0,0,0,.04) 0%, transparent 60%),
    #ece6d6;
  box-shadow: inset 0 0 2px rgba(0,0,0,.15); }
.os-face-art{ display:block; width:100%; height:100%;
  box-shadow: inset 0 0 8px rgba(0,0,0,.25); }
/* Stand-in art panels (production: swap each for a real <img> per face) */
.os-face-art.a1{ background:linear-gradient(135deg,#caa64d,#6b4f1c 60%,#2c2410); }
.os-face-art.a2{ background:linear-gradient(135deg,#7c4f86,#3a2350 55%,#171022); }
.os-face-art.a3{ background:linear-gradient(135deg,#3f8f7e,#1d4f49 55%,#0e2422); }
.os-face-art.a4{ background:linear-gradient(135deg,#4f7bbf,#23406e 55%,#0f1d33); }
.os-face-art.a5{ background:linear-gradient(135deg,#c08a4a,#6e4a22 55%,#2b1d10); }
.os-face-art.a6{ background:linear-gradient(120deg,#c34d72,#3f6db8 45%,#2aa089); }

/* ---- 6-card rail (Pillar B) ----
   All 6 cards live in DOM permanently. JS sets --slot-y (vertical offset)
   and --slot-op (opacity) per card from a continuous browse progress, so
   cards behave like a conveyor: above-fold cards approach from below as
   progress advances, current card sits at center, past cards have lifted
   up and away. No content swap. Same math desktop + mobile (only horiz
   position + width differ via media query). */
.os-card-rail{
  position:absolute; inset:0; z-index:5;
  pointer-events:none;          /* cards opt in via --slot-pe */
  opacity:var(--rail-op, 0);    /* JS controls rail visibility per frame */
}
.os-card{
  position:absolute;
  top:50%;
  z-index:1;
  width:min(350px,30vw);
  pointer-events:var(--slot-pe, none);
  opacity:var(--slot-op, 0);
  /* will-change opt-in: helps the 6 panels stay on the compositor layer
     during continuous translate updates from JS. */
  will-change:transform, opacity;
  transform:translateY(calc(-50% + var(--slot-y, 0px)));
  touch-action:none;
}
.os-card-L{ left:6vw; text-align:left; }
.os-card-R{ left:auto; right:6vw; text-align:right; }
.os-card-rule{ display:block; width:46px; height:1px; background:var(--accent,#c9a84c); margin-bottom:26px; }
.os-card-R .os-card-rule{ margin-left:auto; }
.os-card-tag{ font-family:var(--os-font-mono); font-size:10px;
  letter-spacing:.22em; text-transform:uppercase; color:var(--accent,#c9a84c); margin-bottom:12px; }
.os-card-title{ font-family:var(--os-font-display); font-weight:400;
  font-size:clamp(38px,4.9vw,64px); line-height:.92; letter-spacing:.03em;
  color:#fff; text-shadow:0 2px 26px rgba(0,0,0,.85); margin:0; }
.os-card-body{ font-family:var(--os-font-mono); font-size:12px; line-height:1.68; color:rgba(255,255,255,.58);
  margin:15px 0 22px; text-shadow:0 1px 12px rgba(0,0,0,.9); }
.os-card-R .os-card-body{ margin-left:auto; }

/* Desktop: cards alternate L/R with gold side-border, no glass panel.
   Padding pushes content away from the gold line for breathing room. */
@media (min-width:761px){
  .os-card-L{
    padding:0 0 0 80px;
    border-left:1px solid rgba(212,168,75,.42);
  }
  .os-card-R{
    padding:0 80px 0 0;
    border-right:1px solid rgba(212,168,75,.42);
  }
}

/* ---- Buttons in OFFART site language ---- */
.os-btn-gold{ display:inline-flex; align-items:center; gap:9px; padding:12px 22px;
  justify-content:center;
  border:1px solid transparent; cursor:pointer; background:var(--accent,#c9a84c); color:#15100a;
  font-family:var(--font-tech,"Rajdhani",sans-serif); font-weight:600; font-size:12px;
  letter-spacing:.14em; text-transform:uppercase; border-radius:999px;
  box-shadow:0 6px 22px rgba(201,168,76,.26); max-width:100%;
  transition:background .18s ease,color .18s ease,border-color .18s ease,box-shadow .18s ease; }
.os-btn-gold:hover,
.os-btn-gold:focus-visible{ background:#15100a; color:var(--accent,#c9a84c);
  border-color:var(--accent,#c9a84c); box-shadow:0 8px 24px rgba(201,168,76,.18); }
/* WhatsApp pill — the SVG itself is a green circle (no outer container).
   Desktop 40px (compact next to the gold CTA); mobile 56px (larger tap target). */
.os-btn-wa{ display:inline-flex; width:40px; height:40px; padding:0; text-decoration:none;
  cursor:pointer; background:transparent; border:0; border-radius:50%;
  font-size:0; line-height:0; color:inherit;
  box-shadow:0 6px 18px rgba(37,211,102,.32);
  -webkit-tap-highlight-color:transparent;
  transition:transform .18s ease, filter .18s ease, box-shadow .18s ease; }
.os-btn-wa::before{ content:""; width:100%; height:100%; display:block; border-radius:50%;
  background:url("../icons/os/whatsapp.svg") center/contain no-repeat; }
.os-btn-wa:hover,
.os-btn-wa:focus-visible{ transform:translateY(-1px) scale(1.05);
  filter:brightness(1.06) saturate(1.04);
  box-shadow:0 10px 24px rgba(37,211,102,.46); outline:none; }

/* ---- Final resolve screen ---- */
.os-final{ position:absolute; inset:0; z-index:5; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:20px; text-align:center;
  opacity:0; pointer-events:none; transition:opacity .4s ease; padding:96px 24px 168px; }
.os-final-h{ font-family:var(--os-font-display); font-size:clamp(42px,7vw,82px);
  line-height:.92; letter-spacing:.03em; color:#fff; margin:0; max-width:min(900px,92vw); }
.os-final-sub{ font-family:var(--os-font-mono); color:rgba(255,255,255,.45); font-size:12.5px; letter-spacing:.03em; margin:-8px 0 0; max-width:min(560px,88vw); }
.os-final-acts{ display:flex; flex-direction:column; align-items:center; gap:22px; justify-content:center; margin-top:10px; }
.os-final .os-btn-gold{ min-width:260px; }

/* ---- Hint ---- */
.os-hint{ position:absolute; left:50%; bottom:118px; transform:translateX(-50%); z-index:5;
  font-family:var(--os-font-mono); font-size:11px; letter-spacing:.18em;
  text-transform:uppercase; color:rgba(255,255,255,.4); transition:opacity .4s; pointer-events:none; }

/* ---- No-JS / failsafe fallback ---- */
#offart-os:not(.os-ready) .os-cube{ transform:none; visibility:hidden; }
#offart-os:not(.os-ready) .os-card-rail{ opacity:0; pointer-events:none; }
#offart-os:not(.os-ready) .os-final{ opacity:0; pointer-events:none; }
#offart-os:not(.os-resolved):not(.os-failed) .os-final{ opacity:0!important; pointer-events:none!important; }
#offart-os:not(.os-ready) .os-hint{ opacity:0; }
#offart-os.os-failed .os-final{ opacity:1; pointer-events:auto; }
#offart-os.os-failed .os-scene,
#offart-os.os-failed .os-card-rail{ opacity:0; pointer-events:none; }
/* visibility:hidden hides the cube during the brief window between Stage 5 fade-in
   and boot() running. Without this, the user sees the cube in a default static state
   before JS sets the exploded starting state. The .os-failed class is added only
   by the delayed front-page failsafe, preventing a first-frame resolve-screen flash. */

/* ---- Mobile: smaller cube, all 6 rail cards centered above dock ----
   Cards stack at center anchored ABOVE the dock (no L/R alternation).
   Glass card: dark+alpha bg, faint gold left border, 6px backdrop blur —
   keeps the title legible when the card overlaps the cube. Pattern matches
   the Reverse-Creativity reference (.text-card). */
@media (max-width:760px){
  .os-card,.os-card-L,.os-card-R{
    left:50%; right:auto;
    top:auto;
    bottom:max(168px,calc(env(safe-area-inset-bottom,0px) + 150px));
    transform:translateX(-50%) translateY(var(--slot-y, 0px));
    width:min(88vw,430px); max-width:none; text-align:left;
    padding:24px 20px;
    border:0;
    border-left:1px solid rgba(212,168,75,.20);
    background:rgba(28,24,20,.82);
    overflow:hidden;
    backdrop-filter:blur(6px) saturate(120%);
    -webkit-backdrop-filter:blur(6px) saturate(120%);
  }
  .os-card-rule{ margin-bottom:18px; }
  .os-card-tag{ font-size:9px; letter-spacing:.18em; margin-bottom:8px; }
  .os-card-title{ font-size:clamp(28px,8.4vw,40px); line-height:.95; }
  .os-card-body{ font-size:11.5px; line-height:1.48; margin:10px 0 14px; }
  .os-btn-gold{ padding:10px 18px; font-size:11px; }
  .os-final .os-btn-gold{ min-width:220px; }
  .os-btn-wa{ width:48px; height:48px; }
  /* ::before inherits 100%/100% from base — green circle fills the button,
     no nested icon, no dark wrapper (which is the source of the "black box"
     on mobile in earlier builds). */
  .os-hud{ top:70px; right:16px; }
  .os-cube{ --s:min(62vw,36vh,240px); }
  /* Pillar C item 3 — match the rim-light halo size to the mobile cube formula
     so the halo stays ~1.6x the cube. Without this, the desktop formula above
     keeps the halo at desktop scale and reads as a too-tight ring on mobile. */
  .os-scene::before{
    width:calc(min(62vw,36vh,240px) * 1.6);
    height:calc(min(62vw,36vh,240px) * 1.6);
  }
  .os-hint{ bottom:124px; font-size:9px; }
  .os-final{ padding:88px 20px 152px; gap:16px; }
  .os-final-h{ font-size:clamp(36px,13vw,58px); }
  .os-final-sub{ font-size:11.5px; line-height:1.5; }
}

/* ============================================================
   Interactive overlays — Wacky folder, app windows, splash.
   These were removed when stage-os-screen.css was rewritten
   for the cube; offart-os.js still creates the same DOM, so
   without these rules the folder/window opens invisibly while
   state.folderOpen / state.openWindow blocks all wheel+touch
   input on Stage 5 — visually reads as "frozen".
   z-index ladder: scene=3, hint=5, hud=6, folder=20, window=21,
   splash=30. All below the global .glass-deck dock (z-index:9000).
   ============================================================ */

/* ---- Wacky Ideas folder overlay ---- */
.os-folder-host{
  position:absolute; inset:0; z-index:20;
  display:none; align-items:center; justify-content:center;
  background:radial-gradient(ellipse 90% 80% at 50% 50%, rgba(0,0,0,.55) 0%, rgba(0,0,0,.82) 100%);
  -webkit-backdrop-filter:blur(10px) saturate(112%);
  backdrop-filter:blur(10px) saturate(112%);
  opacity:0; pointer-events:none;
  transition:opacity .28s ease;
}
.os-folder-host.open{ display:flex; opacity:1; pointer-events:auto; }
.os-folder-sheet{
  position:relative;
  width:min(460px, 88%);
  padding:30px 26px 24px;
  border-radius:18px;
  background:
    radial-gradient(ellipse 70% 60% at 30% 0%, rgba(212,168,75,.10), transparent 60%),
    linear-gradient(170deg, rgba(40,30,20,.94) 0%, rgba(20,14,10,.94) 100%);
  border:1px solid rgba(212,168,75,.36);
  box-shadow:
    0 30px 80px -22px rgba(0,0,0,.78),
    0 0 0 1px rgba(255,255,255,.04) inset,
    0 1px 0 rgba(255,235,200,.08) inset;
  transform:translateY(10px) scale(.98);
  opacity:0;
  transition:transform .34s cubic-bezier(.22,1,.36,1), opacity .28s ease;
}
.os-folder-host.open .os-folder-sheet{ transform:none; opacity:1; }
.os-folder-title{
  font-family:var(--os-font-display,"Bebas Neue","Audiowide",sans-serif);
  font-size:20px; letter-spacing:.22em; text-transform:uppercase;
  color:var(--accent,#c9a84c); text-align:center;
  margin:0 0 22px;
}
.os-folder-grid{
  display:grid;
  grid-template-columns:repeat(3, 1fr);
  gap:18px 8px;
  justify-items:center;
}
.os-folder-close{
  all:unset; box-sizing:border-box;
  position:absolute; top:10px; right:12px;
  width:30px; height:30px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:rgba(212,168,75,.10);
  color:var(--accent,#c9a84c);
  font-size:18px; line-height:1; cursor:pointer;
  transition:background .15s ease, transform .15s ease;
}
.os-folder-close:hover{ background:rgba(212,168,75,.22); transform:scale(1.08); }
.os-folder-close:focus-visible{ outline:2px solid var(--accent,#c9a84c); outline-offset:3px; }

/* ---- App tile (used inside folder; also future row tiles) ---- */
.os-app{
  all:unset; cursor:pointer;
  display:flex; flex-direction:column; align-items:center; gap:8px;
  width:78px;
}
.os-app:focus-visible{ outline:2px solid var(--accent,#c9a84c); outline-offset:4px; border-radius:14px; }
.os-app-tile{
  width:58px; height:58px; border-radius:14px;
  display:flex; align-items:center; justify-content:center;
  overflow:hidden;
  background:linear-gradient(160deg, rgba(255,255,255,.10), rgba(255,255,255,.03));
  border:1px solid rgba(212,168,75,.20);
  box-shadow:
    0 6px 18px rgba(0,0,0,.55),
    0 0 0 1px rgba(255,255,255,.04) inset;
  transition:transform .18s cubic-bezier(.22,1,.36,1), border-color .18s ease, box-shadow .18s ease;
}
.os-app-tile img{ width:72%; height:72%; object-fit:contain; display:block; }
.os-app-tile-fallback{
  font-family:var(--os-font-display,"Bebas Neue",sans-serif);
  font-weight:800; color:#fff; font-size:24px; line-height:1;
}
.os-app-label{
  font-family:var(--os-font-mono);
  font-size:10px; letter-spacing:.04em;
  color:rgba(255,255,255,.86); text-align:center; line-height:1.25;
}
.os-app:hover .os-app-tile{
  transform:translateY(-2px);
  border-color:rgba(212,168,75,.55);
  box-shadow:
    0 10px 22px rgba(0,0,0,.6),
    0 0 0 1px rgba(212,168,75,.25) inset;
}
.os-app:active .os-app-tile{ transform:translateY(0) scale(.96); }
.os-app-accent .os-app-tile{
  background:linear-gradient(160deg, rgba(212,168,75,.38), rgba(212,168,75,.10));
  border-color:rgba(212,168,75,.55);
}

/* ---- App window (iframe / internal partial / settings) ---- */
.os-window-host{
  position:absolute; inset:0; z-index:21;
  display:none; align-items:center; justify-content:center;
  background:rgba(0,0,0,.58);
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px);
  opacity:0; pointer-events:none;
  transition:opacity .25s ease;
}
.os-window-host.open{ display:flex; opacity:1; pointer-events:auto; }
.os-window{
  width:min(1100px, 94%);
  height:min(86vh, 860px);
  background:rgba(18,14,10,.96);
  color:#eef2f6;
  border:1px solid rgba(212,168,75,.32);
  border-radius:14px;
  display:flex; flex-direction:column;
  overflow:hidden;
  box-shadow:0 30px 80px rgba(0,0,0,.7);
}
.os-window-bar{
  display:flex; align-items:center; gap:10px;
  padding:12px 18px;
  background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.02));
  border-bottom:1px solid rgba(212,168,75,.18);
  font-family:var(--os-font-mono);
}
.os-window-dot{ display:none; }
.os-window-title{
  font-size:11px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--accent,#c9a84c);
}
.os-window-close{
  margin-left:auto; border:0; background:transparent;
  width:30px; height:30px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  font-size:18px; line-height:1; cursor:pointer;
  color:var(--accent,#c9a84c);
  transition:background .15s ease;
}
.os-window-close:hover{ background:rgba(212,168,75,.16); }
.os-window-close:focus-visible{ outline:2px solid var(--accent,#c9a84c); outline-offset:3px; }
.os-window-body{ flex:1; overflow:auto; background:#0d0907; }
.os-iframe-body{ padding:0; overflow:hidden; }
.os-iframe-frame{ width:100%; height:100%; border:0; display:block; }

/* Settings window (builtin) */
.os-window-settings .os-window-body{ padding:24px; }
.os-settings-menu{ list-style:none; padding:0; margin:0; }
.os-settings-menu li{ margin:0 0 14px; }
.os-settings-menu a{
  display:block; padding:14px 18px; border-radius:10px;
  background:rgba(255,255,255,.04);
  border:1px solid rgba(212,168,75,.18);
  color:#eef2f6; text-decoration:none;
  font-family:var(--os-font-mono); font-size:13px;
  transition:background .15s ease, border-color .15s ease;
}
.os-settings-menu a:hover{
  background:rgba(212,168,75,.08);
  border-color:rgba(212,168,75,.40);
}

/* ---- Splash (page navigation transition) ---- */
.os-splash{
  position:absolute; inset:0; z-index:30;
  display:flex; align-items:center; justify-content:center; flex-direction:column; gap:18px;
  background:radial-gradient(ellipse at 50% 50%, #1c1612 0%, #050302 100%);
  opacity:0; pointer-events:none;
  transition:opacity .25s ease;
}
.os-splash.show{ opacity:1; pointer-events:auto; }
.os-splash-mark{
  font-family:var(--os-font-display,"Bebas Neue","Audiowide",sans-serif);
  font-size:32px; letter-spacing:.22em; color:var(--accent,#c9a84c);
}
.os-splash-spinner{
  width:28px; height:28px; border-radius:50%;
  border:2px solid rgba(212,168,75,.18);
  border-top-color:var(--accent,#c9a84c);
  animation:os-splash-spin .9s linear infinite;
}
@keyframes os-splash-spin{ to{ transform:rotate(360deg); } }

/* ---- Global dock hide while an OS window is open ----
   The inline script in stage-os-screen.php toggles body.offart-os-window-open
   when #os-window-host opens (MutationObserver). The dock (#global-dock
   .glass-deck, z-index:9000, body-level fixed-bottom) would otherwise overlap
   the app. :has() is a no-JS modern-browser fallback. The folder modal is a
   small centered sheet, NOT a full app, so the dock stays visible there. */
body.offart-os-window-open #global-dock,
body:has(#os-window-host.open) #global-dock{
  display:none !important;
}

/* ---- Mobile (≤760px) ---- */
@media (max-width:760px){
  .os-folder-sheet{ width:min(420px, 92%); padding:26px 18px 20px; }
  .os-folder-title{ font-size:17px; margin-bottom:18px; }
  .os-folder-grid{ gap:16px 6px; }
  .os-app{ width:68px; }
  .os-app-tile{ width:52px; height:52px; border-radius:13px; }
  .os-app-label{ font-size:9.5px; }
  /* Mobile windows behave like full-screen apps (Wacky inner apps + FAQ
     iframe). No window-frame chrome — slim top bar with a back-arrow,
     iframe fills the rest. Browser back / pushState in the inline script
     already returns to the cube.
     Hosts switch to position:fixed because .stage has padding-top:60px +
     padding-bottom:100px (stages.css), so the absolute-positioned host
     would cover only the stage CONTENT box — not the viewport — and the
     window's flex-centered placement leaks past the stage's overflow:hidden
     edges. fixed (no transformed ancestor; front-page.php enforces
     transform:none on #page/.site).
     IMPORTANT: use height:100dvh, NOT inset:0. On iOS Safari, inset:0 on
     a fixed element pins to the LAYOUT viewport (which extends BEHIND the
     address bar + home indicator), so the iframe's own position:fixed
     bottom-0 elements (WhatsArt chat, LinkedArt footer) render below the
     visible area. 100dvh resolves to the VISUAL viewport and updates as
     browser chrome shows/hides. */
  .os-window-host,
  .os-folder-host,
  .os-splash{
    position:fixed;
    top:0; left:0; right:0; bottom:auto;
    height:100dvh;
  }
  .os-window-host{ background:#0a0604; -webkit-backdrop-filter:none; backdrop-filter:none; }
  .os-window{
    width:100%; height:100%; max-width:none;
    border-radius:0; border:0;
    box-shadow:none;
    padding-top:env(safe-area-inset-top,0);
  }
  .os-window-bar{
    padding:10px 14px; min-height:44px;
    background:rgba(18,14,10,.96);
    border-bottom:1px solid rgba(212,168,75,.22);
  }
  .os-window-title{ font-size:11px; letter-spacing:.14em; }
  /* Back-arrow look: hide the &times; glyph and paint a ‹ via pseudo. JS
     keeps innerHTML="×" (no JS change needed), CSS just swaps the visual. */
  .os-window-close{
    order:-1; margin:0 6px 0 -4px;
    width:38px; height:38px; min-height:44px;
    font-size:0;
    background:transparent;
  }
  .os-window-close::before{
    content:"‹";
    font-family:var(--os-font-display,"Bebas Neue",sans-serif);
    font-size:30px; line-height:1;
    color:var(--accent,#c9a84c);
  }
  .os-window-close:hover{ background:rgba(212,168,75,.10); }
  .os-iframe-frame{ height:100%; }
  /* Settings window: keep modal-ish on mobile too, but full-bleed body. */
  .os-window-settings .os-window-body{ padding:18px; }
  .os-splash-mark{ font-size:26px; }
}

@media (prefers-reduced-motion:reduce){
  .os-folder-host,
  .os-folder-sheet,
  .os-window-host,
  .os-splash,
  .os-app-tile,
  .os-window-close,
  .os-folder-close{
    transition:none !important;
    animation:none !important;
  }
  .os-folder-sheet{ transform:none; }
  .os-splash-spinner{ animation:none !important; }
}
