/* =========================================================================
   sandbox.css — the sand-walk demo, portable.

   WHAT THIS IS. The third extraction in the same series as walker_tokens.css
   (the :root block) and walker_nav.css (the bar): the rules a page needs to
   render the sand walk, and nothing else. Any page that wants the demo loads
   this; the page keeps its own reset, its own header and its own background.

   WHY IT HAD TO BE EXTRACTED. The sandbox rules lived in styles.css, which
   opens with `*{margin:0;padding:0;box-sizing:border-box}` — a full reset —
   and goes on to claim `header`, `.nav`, `.logo`, `.hero`, `.wrap` and
   `img{max-width:100%}`. On a WordPress page that reset flattens every margin
   Foundation and the theme depend on, and `.logo` restyles the site wordmark.
   walked-shell.css is no better: `*{box-sizing}`, a `body{}` gradient over the
   whole viewport, and `a{color:inherit;text-decoration:none}` stripping every
   underline on the page. Neither file can be loaded next to a theme, and all
   four .sandbox rules were inside the first one.

   THREE LAYERS, RESOLVED ONCE. On walked.html the demo's real appearance is
   the sum of styles.css (base), recolor.css (gold remap) and walked-shell.css
   lines 296-337 (gold -> aqua, with the contrast corrections). Carrying that
   stack would mean shipping two files whose only job is to undo the first.
   Every rule below is the END STATE, with var(--brass) already resolved to the
   role the reconciliation block assigned it:

       surface (borders, outlines, rings)   -> var(--accent)       3:1 floor
       text, and fills behind white text    -> var(--accent-deep)  4.5:1 floor

   That is why nothing here says var(--brass). The alias still exists in
   walker_tokens.css for accordion.css and walker_bag.css; this file does not
   need it and using it would re-open the contrast bug the block above fixed.

   SCOPED, NOT GLOBAL. .step, .shell, .wave, .grain, .bottle and .stepper are
   names any theme might already own. Everything that lives inside the stage is
   scoped under .sandbox and everything around it under .demo-card, so this
   file cannot reach an element it does not own. .mail-note and .fs-toast are
   the exceptions: logic.js appends both to <body> to escape the sandbox's
   overflow:hidden, so they cannot be nested — their names carry them.

   REQUIRES walker_tokens.css, loaded first, for --ink, --ink-soft, --cream,
   --panel, --accent, --accent-deep, --sans and --serif.

   THE MARKUP IS A CONTRACT. logic.js lines 1-8 read #leftInput, #rightInput
   and #sandbox with const at module top level and no guards; line 149 calls
   .addEventListener on them. A page that loads the script without the markup
   throws before anything runs.
   ========================================================================= */

/* =========================================================================
   1. The stencil face.

   Was 28,728 characters of base64 at styles.css line 1 — 60 percent of that
   file, re-parsed on every load and impossible to edit around. Self-hosted for
   the same reason walker_tokens.css self-hosts Jost and Marcellus:
   oc.class.php prepends the store URL to hrefs it emits, so an absolute URL is
   the only kind that survives the WordPress/OpenCart bridge intact.

   'Saira Stencil One' stays in the stack as it always was, but it came from
   the Google Fonts link in walked.html's <head> and is NOT available on a page
   that does not carry that link. It is a load-window fallback here, not a
   second face.
   ========================================================================= */
@font-face{
  font-family:'ArialStencil';
  src:url('https://flipsidez.com/webfonts/ArialStencil.woff2') format('woff2');
  font-display:swap;
}

/* =========================================================================
   2. Tokens the beach owns.

   recolor.css remapped --ink, --brass and --shell to the approved palette and
   deliberately left these alone: the sand is photographic, not brand, and
   re-tinting it with the accent would turn the beach aqua. --tide is the
   corporate segment colour, borrowed here for success states only.

   --shell aliases --cream rather than restating #f6f1e6, so a change to the
   surface colour travels from one place.
   ========================================================================= */
:root{
  --sand:#E9DDC4;        /* dry sand   */
  --sand-deep:#C9B48D;   /* wet sand   */
  --imprint:#A78D5F;     /* pressed sand */
  --tide:#1F5E63;        /* success / ready states */
  --shell:var(--cream);
}

/* =========================================================================
   3. The stage.
   ========================================================================= */
.demo-card{position:relative}

.demo-card .demo-label{font-size:.72rem;letter-spacing:.24em;text-transform:uppercase;
  font-weight:500;color:var(--ink-soft);margin-bottom:14px;display:flex;align-items:center;gap:10px}
.demo-card .demo-label::after{content:"";flex:1;height:1px;background:rgba(69,67,60,.3)}

.sandbox{position:relative;border-radius:6px;padding:30px 26px;overflow:hidden;
  background:linear-gradient(160deg,#E6D7B8 0%,#D8C49C 55%,#CBB387 100%);
  box-shadow:inset 0 2px 18px rgba(120,95,55,.28), 0 24px 50px -28px rgba(28,43,51,.45)}

/* Grain. An inline SVG turbulence filter rather than a bitmap: it tiles at any
   size and costs one paint. url() in a stylesheet resolves against the SHEET,
   not <base>, so this survives the /shop/ base href untouched. */
.sandbox::before{content:"";position:absolute;inset:0;opacity:.65;mix-blend-mode:multiply;
  z-index:2;pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='s'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.1' numOctaves='3'/%3E%3CfeColorMatrix values='0 0 0 0 .6 0 0 0 0 .5 0 0 0 0 .33 0 0 0 .22 0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23s)'/%3E%3C/svg%3E")}

.sandbox .sole-demo{display:block;width:100%;height:auto;overflow:visible}
.sandbox .sole-text{font-family:'ArialStencil','Saira Stencil One',sans-serif;
  fill:#DCC89C;letter-spacing:.04em}
.sandbox .shell{filter:drop-shadow(0 1.5px 1px rgba(82,63,33,.35))}
.sandbox .bottle{cursor:pointer;filter:drop-shadow(0 2px 2px rgba(82,63,33,.4))}
.sandbox #layerPrints,
.sandbox #layerGrains,
.sandbox #layerShells{pointer-events:none}   /* taps reach the bottle under prints */

/* ---- the tide ---- */
.sandbox .wave{position:absolute;left:-2%;width:104%;top:0;height:118%;z-index:4;
  pointer-events:none;transform:translateY(-112%)}
.sandbox .wave svg{display:block;width:100%;height:100%}
.sandbox.washing .wave{animation:wash calc(var(--waveMs,2800)*1ms) ease-in-out forwards}
@keyframes wash{
  0%{transform:translateY(-110%)}
  42%{transform:translateY(-4%)}                      /* surge down the beach */
  58%{transform:translateY(-4%)}                      /* linger at full reach */
  100%{transform:translateY(-110%)}                   /* recede to the sea */
}

/* ---- the footstep ----
   Heel strikes fast, weight rolls slowly through the midfoot, toe presses off.
   The timing functions live on the keyframes because each phase has a
   different one. */
.sandbox .step{opacity:0;clip-path:inset(-6% 106% -6% -6%)}
.sandbox .step.live{animation:press calc(var(--revealMs,300)*1ms) forwards;
  animation-delay:var(--stepDelay,0ms)}
@keyframes press{
  0%{opacity:0;clip-path:inset(-6% 106% -6% -6%);animation-timing-function:ease-out}
  6%{opacity:1}
  22%{clip-path:inset(-6% 60% -6% -6%);animation-timing-function:ease-in-out}   /* heel planted */
  62%{clip-path:inset(-6% 32% -6% -6%);animation-timing-function:ease-in}       /* midfoot roll */
  100%{opacity:1;clip-path:inset(-6% -6% -6% -6%)}                              /* toe-off */
}

.sandbox .grain{opacity:0;animation:grainFall var(--gdur,700ms) ease-in var(--gdelay,0ms) forwards}
@keyframes grainFall{
  0%{opacity:0;transform:translate(var(--gx0,0px),var(--gy0,-60px))}
  18%{opacity:1}
  100%{opacity:.85;transform:translate(0,0)}
}

/* =========================================================================
   4. The message in a bottle.
   ========================================================================= */
.sandbox .bottle-note{position:absolute;inset:0;z-index:5;display:flex;
  align-items:center;justify-content:center;background:rgba(28,43,51,.25)}
.bottle-note .note-card{background:#FBF5E6;border:1px solid var(--sand-deep);border-radius:4px;
  box-shadow:0 18px 40px -16px rgba(28,43,51,.5);padding:26px 30px;text-align:center;
  max-width:78%;position:relative}
.bottle-note h4{font-family:var(--serif);font-weight:400;font-size:1.15rem;margin-bottom:6px}
.bottle-note p{font-size:.85rem;color:var(--ink-soft);margin-bottom:14px}

/* The promo code is READ, so it takes the deep end. On the surface accent it
   would land at 3.47:1 — the contrast bug walked-shell.css:296 documents. */
.bottle-note .code{font-family:'ArialStencil','Saira Stencil One',sans-serif;font-size:1.4rem;
  letter-spacing:.12em;color:var(--accent-deep);border:1.5px dashed var(--accent-deep);
  border-radius:3px;padding:8px 18px;display:inline-block;cursor:pointer;transition:background .2s}
.bottle-note .code:hover{background:rgba(54,149,171,.12)}
.bottle-note .copied{font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--tide);margin-top:10px;min-height:1em}
.bottle-note .note-close{position:absolute;top:6px;right:12px;border:none;background:none;
  font-size:1.3rem;color:var(--ink-soft);cursor:pointer;line-height:1}

/* =========================================================================
   5. Controls under the stage.
   ========================================================================= */
.demo-card .clear-btn{font-family:var(--sans);font-size:.78rem;letter-spacing:.14em;
  text-transform:uppercase;font-weight:500;padding:13px 20px;border:1px solid rgba(28,43,51,.25);
  background:#fff;color:var(--ink);border-radius:3px;cursor:pointer;transition:all .2s}
.demo-card .clear-btn:hover{border-color:var(--ink);background:var(--ink);color:var(--shell)}
.demo-card .clear-btn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

/* Walk composes with .clear-btn — it carries colour only, never geometry. */
.demo-card .walk-btn{background:var(--ink);color:var(--shell);border-color:var(--ink)}
.demo-card .walk-btn.walk-active,
.demo-card .walk-btn:hover{background:var(--accent-deep);border-color:var(--accent-deep);color:#fff}

.demo-card .btn-stack{display:flex;flex-direction:column;gap:6px}
.demo-card .btn-stack .clear-btn{padding:5px 20px}

.demo-card .stepper{display:flex;align-items:center;border:1px solid rgba(28,43,51,.25);
  border-radius:3px;background:#fff;overflow:hidden}
.demo-card .stepper button{font-family:var(--sans);font-size:1rem;font-weight:500;width:34px;
  padding:11px 0;border:none;background:transparent;color:var(--ink);cursor:pointer;
  transition:background .2s}
.demo-card .stepper button:hover{background:var(--ink);color:var(--shell)}
.demo-card .stepper button:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.demo-card .stepper output{flex:1;text-align:center;font-size:.92rem;min-width:48px}

.demo-card .demo-input-row{display:flex;gap:10px;margin-top:18px;align-items:flex-end;flex-wrap:wrap}
.demo-card .demo-field{flex:1;display:flex;flex-direction:column;gap:5px}
.demo-card .demo-field.narrow{flex:0 0 110px}
.demo-card .demo-field span{font-size:.66rem;letter-spacing:.22em;text-transform:uppercase;
  font-weight:600;color:var(--ink-soft)}
.demo-card .demo-input-row input{width:100%;font-family:var(--sans);font-size:1rem;
  padding:13px 16px;border:1px solid rgba(28,43,51,.25);background:#fff;color:var(--ink);
  border-radius:3px}
.demo-card .demo-input-row input:focus{outline:2px solid var(--accent);outline-offset:1px;
  border-color:var(--accent)}
.demo-card .demo-hint{font-size:.8rem;color:var(--ink-soft);margin-top:10px;font-style:italic}

/* The tuning controls ship hidden and stay in the DOM with their defaults, so
   the walk still reads them. The [+] toggle puts .dev-shown on <body>. */
.demo-card .demo-input-row .dev{display:none}
body.dev-shown .demo-card .demo-input-row .demo-field.dev{display:flex}
body.dev-shown .demo-card .demo-input-row .clear-btn.dev{display:inline-block}

/* Video capture. #videoBtn is an id in walked.html's own markup — left
   unscoped because an id is already unique to the document. */
#videoBtn.recording{background:#15c64e!important;border-color:#15c64e!important;color:#fff!important;
  pointer-events:none;box-shadow:0 0 0 0 rgba(21,198,78,.55);animation:recPulse 1.1s ease-out infinite}
@keyframes recPulse{
  0%{box-shadow:0 0 0 0 rgba(21,198,78,.55)}
  70%{box-shadow:0 0 0 13px rgba(21,198,78,0)}
  100%{box-shadow:0 0 0 0 rgba(21,198,78,0)}
}
#videoBtn.ready{background:var(--tide);border-color:var(--tide);color:var(--shell)}

/* =========================================================================
   6. Overlays.

   NOT scoped, and it is not an oversight: logic.js appends both to <body> to
   escape .sandbox's overflow:hidden, so there is no ancestor to scope them to.
   Their names are distinctive enough to carry the isolation on their own.
   ========================================================================= */
.mail-note{position:fixed;inset:0;z-index:1000}
.mail-note .note-card{max-width:92vw;width:420px;text-align:left;max-height:90vh;
  overflow-y:auto;padding:22px 24px}
.mail-note label{display:block;font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;
  font-weight:600;color:var(--ink-soft);margin:9px 0 4px}
.mail-note label .opt{text-transform:none;letter-spacing:0;font-weight:400}
.mail-note input,
.mail-note textarea{width:100%;font-family:var(--sans);font-size:16px;padding:8px 11px;
  border:1px solid rgba(28,43,51,.25);border-radius:3px;background:#fff}
.mail-note textarea{resize:none}
.mail-note .mail-actions{display:flex;gap:8px;margin-top:12px}
.mail-note .mail-actions button{flex:1;padding:9px 0;font-size:.72rem;white-space:nowrap;
  display:inline-flex;align-items:center;justify-content:center;gap:6px}
.mail-note .mail-hint{font-size:.7rem;color:var(--ink-soft);margin-top:7px;text-align:center}
.mail-note .mail-status{font-size:.88rem;font-weight:500;color:var(--tide);margin-top:12px;
  min-height:1.2em;text-align:center}
.mail-note button:disabled{opacity:.5;pointer-events:none}

.fs-toast{position:fixed;left:50%;bottom:34px;transform:translateX(-50%) translateY(12px);
  z-index:1100;background:var(--ink);color:var(--shell);font-family:var(--sans);font-size:.92rem;
  letter-spacing:.03em;padding:13px 22px;border-radius:7px;
  box-shadow:0 16px 38px -14px rgba(28,43,51,.6);opacity:0;
  transition:opacity .26s ease,transform .26s ease;pointer-events:none;display:flex;
  align-items:center;gap:10px;max-width:88vw}
.fs-toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
.fs-toast .fs-toast-check{display:inline-flex;width:19px;height:19px;border-radius:50%;
  background:#15c64e;color:#fff;align-items:center;justify-content:center;font-size:.72rem;
  font-weight:700;flex:none}

/* =========================================================================
   7. Chrome that logic.js styles at runtime.

   logic.js injects a <style> block holding the base rules for the symbol
   chart, the segment buttons and the section headings — which lands AFTER this
   file in the document and would otherwise win on order alone. The `body`
   prefix is what outranks it. This is the one place in the file where a
   selector is deliberately made heavier than it looks.
   ========================================================================= */
body .ds-head{font-family:var(--serif);color:var(--ink)}
body .ds-sub{color:var(--ink-soft)}

body .symbol-chart{background:var(--panel);border-color:rgba(54,149,171,.40)}
body .symbol-chart .chart-hint,
body .symbol-chart .sym-skip,
body .symbol-chart .sym-tile span{color:var(--ink-soft)}
body .symbol-chart .sym-tile svg{fill:var(--ink-soft)}
body .symbol-chart .sym-tile{border-color:rgba(54,149,171,.35)}
body .symbol-chart .sym-tile:hover{background:rgba(54,149,171,.12);border-color:var(--accent)}
body .symbol-chart .sym-skip{border-color:rgba(54,149,171,.55)}

body .seg-btn{border-right-color:rgba(54,149,171,.50)}
body .seg-btn.seg-clear{color:var(--accent-deep)}
body .seg-btn.seg-halt.on{background:var(--accent-deep)}

/* [+] reveal toggle — a round button after Share. */
body .dev-toggle{display:inline-grid;place-items:center;vertical-align:middle;margin-left:8px;
  width:30px;height:30px;border-radius:50%;cursor:pointer;line-height:1;font-size:18px;
  font-weight:400;color:var(--ink);background:var(--panel);
  border:1px solid rgba(54,149,171,.55);
  transition:background .2s, color .2s, border-color .2s}
body .dev-toggle:hover{background:var(--accent-deep);border-color:var(--accent-deep);color:#fff}
body .dev-toggle:focus-visible{outline:none;box-shadow:0 0 0 3px rgba(54,149,171,.3)}

body .fs-aud{display:flex;flex-wrap:wrap;align-items:center;gap:8px 22px;margin:4px 0 16px;
  font-size:13px;color:var(--ink-soft)}
body .fs-aud-lbl{flex-basis:100%;font-size:.66rem;letter-spacing:.2em;text-transform:uppercase;
  font-weight:600;color:var(--ink-soft);margin-bottom:3px}
body .fs-aud label{display:inline-flex;align-items:center;gap:6px;cursor:pointer;line-height:1;
  font-size:.95rem;color:var(--ink)}
body .fs-aud input{accent-color:var(--accent);margin:0;width:16px;height:16px;flex:none}

/* =========================================================================
   8. Phone.

   The beach crops to its centre and zooms so the prints stay readable, and the
   controls become a grid: two text fields side by side, Walk and Clear
   full-width below, all thumb-sized.
   ========================================================================= */
@media(max-width:640px){
  .sandbox .sole-demo{height:235px}
  .sandbox{padding:18px 14px}

  .demo-card .demo-input-row{display:grid;grid-template-columns:1fr 1fr;gap:10px;align-items:end}
  .demo-card .demo-field.narrow{grid-column:1 / -1;flex-basis:auto}
  .demo-card .walk-btn,
  .demo-card .clear-btn{width:100%}

  /* Compact action bar: Add a Symbol, Clear, Walk and Share share one row so
     they stay visible when the symbol chart opens below them. */
  .ds-actions-compact{display:flex;flex-wrap:nowrap;gap:6px;align-items:stretch}
  .ds-actions-compact > *{flex:1 1 0;min-width:0;width:auto;margin:0}
  .ds-actions-compact #symbolBtn{height:auto!important;padding:7px 4px;font-size:.58rem;line-height:1.1}
  .ds-actions-compact .clear-btn{padding:7px 4px;font-size:.62rem;letter-spacing:.03em;white-space:nowrap}
  .ds-actions-compact .ds-share{letter-spacing:.04em}
}

/* =========================================================================
   9. Reduced motion.

   Scoped to the sandbox. styles.css did this with a global `*{animation:none}`,
   which on a host page would stop every animation the theme owns — not this
   file's call to make. walker_tokens.css already handles transitions globally.
   ========================================================================= */
@media(prefers-reduced-motion:reduce){
  .sandbox *{animation:none!important}
  .sandbox .step{opacity:1!important;clip-path:none!important}
  .sandbox .grain{display:none}
}
