NewLink Testing catches survey errors before fieldwork.Try it free
Draft — this post is not published to production
Learn

How to build a social feed with ad exposure timing in Decipher

Build a five-page Decipher social feed from copyable XML, CSS and JavaScript sections. Understand native Likes, content assignments, exposure timing and the final code.

A Decipher social feed showing a fictional person's bicycle photo with a Like control, followed by a sponsored Kettle and Kind post.

This guide builds a scrolling social feed inside a Decipher survey. Respondents browse organic posts and sponsored ads, Like the posts that stand out, and continue to the next feed. The survey records their current Likes, the content assigned to each position, and how long each card qualifies as visible.

The social-feed example on GitHub includes five feeds of 20 posts. Each feed contains 16 organic posts and four sponsored ads. The people, brands, copy and images are synthetic. This is a survey activity that follows familiar feed conventions; it does not connect to a social-media account.

You will assemble the same complete XML shown at the end. Start with the document scaffold, replace each named insertion point, and follow the explanation beside each section. The screenshot above shows the finished element.

1. Prepare the survey and files

Create a new Decipher survey in testing mode with XML editing and system/static upload access. Download the social-feed example files.

UploadLocationPurpose
social-design.datRoot/system filesAssignments for eight versions of five feeds.
All 26 JPEGs in assets/images/Static/public filesTen avatars and sixteen post photos.

Upload the JPEGs under their existing filenames, such as avatar-01.jpg and image-11.jpg, without adding an images/ directory to their public names. The XML uses [rel ...] references; Forsta documents them in its static-file guide. The supplied design/resources are enough to build the example; no external JavaScript or Python build is needed.

2. Start with the XML structure

Open the XML editor of your new test survey. Replace its contents with this scaffold; do not nest it inside another <survey> element.

The outer <style name="respview.client.css"> is a Decipher XML hook. The inner <style> is the HTML stylesheet it emits. Paste CSS rules between that inner pair. <![CDATA[ and ]]> protect characters such as < and & from XML parsing. Keep the backslash in \@media and \@keyframes; these examples escape those rules for Decipher's style processing.

respview.client.js is the JavaScript hook. Its exact wrapper is already in the scaffold below. Both hooks are children of <survey>, alongside the questions. Python belongs in <exec> or <validate> inside the XML, never in the JavaScript hook. Forsta describes the embedding rules in its XML style-system guide.

The BUILD: comments are temporary insertion points. Replace the entire named comment line with its matching code block, once. Keep the surrounding opening and closing tags. Each block below is part of the finished document, with no omitted rows or helper functions. Complete all replacements before saving and running the survey; an unfinished script can refer to functions or variables you have not inserted yet. The final example is an alternative one-paste installation, not another block to append.

Here, mode="after" appends to the normal hook. wrap="ready" makes Decipher supply the JavaScript script tag and document-ready wrapper. Paste the JavaScript inside its CDATA; do not add another HTML <script> there.

Part of the documentJob
CSS hookPage theme, feed appearance and early loading reveal.
JavaScript hookTiming library, input mapping, Likes, caching and measurement lifecycle.
Initialization, resources and assignmentResolve content and retain its design/version identifiers.
OfferN, TimeN, HeaderN, FeedN, page breakOne complete feed page, repeated for N = 1 through 5.
<survey
  name="Social feed"
  alt="Social feed"
  compat="144"
  fir="on"
  html:showNumber="0"
  builder:wizardCompleted="1"
  state="testing"
  ss:enableNavigation="0"
  extraVariables="source"
>
  <style name="respview.client.css" mode="after"><![CDATA[
    <!-- questra-theme:start -->
    <style>
      /* BUILD: THEME_PAGE */
      /* BUILD: THEME_CONTROLS */
      /* BUILD: THEME_GATE_CSS */
    </style>
 
    <script>
      /* BUILD: THEME_GATE_JS */
    </script>
    <!-- questra-theme:end -->
    <style>
      /* BUILD: FEED_PAGE */
      /* BUILD: FEED_CARDS */
      /* BUILD: FEED_MEDIA_LIKE */
      /* BUILD: FEED_ANIMATION */
    </style>
  ]]></style>
  <style name="respview.client.js" mode="after" wrap="ready"><![CDATA[
    /* Shared by the native component and deterministic timing tests. */
    (function (scope) {
      'use strict';
      /* BUILD: FEED_METER */
      /* BUILD: FEED_FULL_FRACTION */
      const api = { fraction, fullFraction, meter };
      if (typeof module !== 'undefined' && module.exports) module.exports = api;
      else scope.SocialFeedTiming = api;
    })(typeof window === 'undefined' ? globalThis : window);
 
    (function () {
      'use strict';
      /* BUILD: FEED_DISCOVERY */
      /* BUILD: FEED_RESTORE_SETUP */
      /* BUILD: FEED_SAVE_RENDER */
      /* BUILD: FEED_BUILD */
      /* BUILD: FEED_SAMPLE */
      /* BUILD: FEED_LIFECYCLE */
    })();
 
    if (window.QuestraTheme) window.QuestraTheme.ready();
  ]]></style>
  <!-- BUILD: FEED_LOADER -->
  <!-- BUILD: FEED_ORGANIC -->
  <!-- BUILD: FEED_ADS_IMAGES -->
  <!-- BUILD: FEED_ASSIGNMENT -->
  <!-- BUILD: FEED_ONE_OFFERS -->
  <!-- BUILD: FEED_ONE_TIME -->
  <!-- BUILD: FEED_ONE_QUESTION -->
  <!-- BUILD: FEED_2_PAGE -->
  <!-- BUILD: FEED_3_PAGE -->
  <!-- BUILD: FEED_4_PAGE -->
  <!-- BUILD: FEED_5_PAGE -->
  <!-- BUILD: FEED_FOOTER -->
</survey>

Read the opening <survey> settings before adding the component:

SettingWhy it is here
name, altThe survey's name and alternate title. They do not determine answer codes.
compat="144"Retains the source example's compatibility level. Changing it can change the generated markup the script reads.
fir="on"Enables Decipher's form input replacement presentation; the underlying native inputs still exist.
html:showNumber="0"Suppresses displayed question numbers.
builder:wizardCompleted="1"Retains the example's completed setup-wizard flag.
state="testing"Keeps the example in its testing lifecycle.
ss:enableNavigation="0"Does not add Decipher's Back navigation button.
extraVariables="source"Includes the URL variable source in the survey's extra variables.

These are survey settings, separate from the component's own logic. See Forsta's survey-tag reference and compatibility-level reference.

Read the syntax used in the build

In XML, label gives an element its programmatic identity; value declares an exported answer code. <title> and <comment> provide question text and instructions. <suspend /> ends a page. A where="execute" field runs on the server without being shown to the respondent. optional="0" requires an answer; optional="1" allows a field to be empty. A numeric field's size is its input width, not an allowed-value list.

In JavaScript, querySelector finds one matching element and querySelectorAll finds all matches. A Map or object connects a stable identifier to its native input. data-* HTML attributes become element.dataset properties. forEach visits every entry; map produces a new list; find returns the first match; some and every test whether any or all entries qualify. A guard followed by return stops that function when its prerequisites are absent.

The immediately invoked function, (function () { ... })();, keeps local variables out of the global scope. Its opening and closing punctuation is already in the scaffold; the dots in this sentence are explanatory, not a code block to paste. 'use strict' enables stricter JavaScript checks. Event listeners connect named actions to clicks, keys or pointer movement. textContent inserts plain text; innerHTML builds the example's HTML elements. aria-*, role and tabIndex describe controls and keyboard focus to assistive technology. They supplement the native inputs rather than creating exported answers.

For CSS, read each selector as “which elements” and the declarations inside its braces as “how they look.” margin, padding and gap control space outside, inside and between elements. width, height, min-*, max-* and box-sizing control dimensions. Flex/grid rules arrange children. position, edge offsets and z-index place layers; transform moves or scales them; opacity changes transparency. Fonts, colors, borders, radii and shadows provide the visual treatment. transition animates a property change; animation runs named keyframes. Attribute selectors such as [aria-pressed='true'] style a state the script sets. Media queries apply only at the specified width or motion preference.

3. Build the native survey and data flow

These blocks belong in the XML part of the scaffold, outside the client CSS and JavaScript hooks. Keep Python indentation exactly as shown; Python uses indentation to define its blocks.

1. Load all content assignments on the server

Replace the entire BUILD: FEED_LOADER comment line in the XML scaffold with this block.

loadSocialDesign() opens the system file relative to gv.survey.path, splits tab-separated records, closes the file and skips the header. It converts the first three columns into a (version, task, concept) tuple key and the remaining columns into an integer list.

The supplied file contains eight versions × five feeds × twenty positions: 800 data rows. Its columns are Version, Task, Concept, Copy, Image, Order, Item, Kind, Creative, Campaign and Context. Therefore the stored list indices 0–7 mean copy, image, display order, item, kind, creative, campaign and context. Kind is zero for organic and one for sponsored content. The browser will display these assignments rather than choose them.

  <exec when="init"><![CDATA[
def loadSocialDesign(fname):
    f = open("%s/%s" % (gv.survey.path, fname))
    records = [line.strip("\r\n").split("\t") for line in f.readlines()]
    f.close()
    design = {}
    for row in records[1:]:
        design[(int(row[0]), int(row[1]), int(row[2]))] = [int(n) for n in row[3:]]
    return design
socialDesign = loadSocialDesign("social-design.dat")
]]></exec>

2. Define the thirty organic content records

Replace the entire BUILD: FEED_ORGANIC comment line in the XML scaffold with this block.

Each group of three <res> elements defines one copy level. copyN holds the caption, bylineN holds its author row, and offerN is empty for organic content. The resource label is the lookup key; the number after it connects a caption to its byline and offer. These are reusable content definitions, not separate survey pages.

The byline HTML contains an avatar image and author/date details. data-src holds a survey-relative image URL without loading it in the hidden native matrix. Width and height reserve the avatar's size, an empty alt marks it decorative, and the source/date text remains readable. The SVG path in the metadata draws a small decorative icon. CDATA protects that HTML, while [rel avatar-NN.jpg] resolves the uploaded filename. The thirty groups vary the content; their structure is identical.

  <res label="copy1">Sunday bread experiment, attempt number four. Finally got the crust right. Half of this disappeared before it had even cooled down 😂</res>
  <res label="byline1"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-09.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Maya Bennett</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer1"><![CDATA[]]></res>
  <res label="copy2">We said we were going for a quick walk. Three hours and one very steep hill later… absolutely worth it.</res>
  <res label="byline2"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-02.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Ben Carter</div><div class="cf-post-meta"><span>38 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer2"><![CDATA[]]></res>
  <res label="copy3">Took the long way home and found this little street. Making a mental note to come back when the roses are out.</res>
  <res label="byline3"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-03.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Elena Morris</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer3"><![CDATA[]]></res>
  <res label="copy4">A few days by the sea was exactly what we needed. This was the view on the morning coffee walk.</res>
  <res label="byline4"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-04.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Sam Rivera</div><div class="cf-post-meta"><span>3 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer4"><![CDATA[]]></res>
  <res label="copy5">Three weeks ago these were tiny cuttings in a jam jar. Now I apparently have a windowsill herb garden 🌱</res>
  <res label="byline5"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-05.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Priya Shah</div><div class="cf-post-meta"><span>54 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer5"><![CDATA[]]></res>
  <res label="copy6">Rain canceled our plans, so I’m calling this an excellent alternative. Tea, a blanket and the book I keep meaning to finish.</res>
  <res label="byline6"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-06.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Jordan Ellis</div><div class="cf-post-meta"><span>25 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer6"><![CDATA[]]></res>
  <res label="copy7">First watercolor class done. The sky was supposed to be blue, but I’m choosing to call it creative freedom.</res>
  <res label="byline7"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-07.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Theo Park</div><div class="cf-post-meta"><span>4 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer7"><![CDATA[]]></res>
  <res label="copy8">Our extremely ambitious weekend plan: bring lunch to the park and stay until the coffee runs out.</res>
  <res label="byline8"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-08.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Amara Brooks</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer8"><![CDATA[]]></res>
  <res label="copy9">The kitchen smells incredible. Trying very hard to save some of this loaf for breakfast tomorrow.</res>
  <res label="byline9"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-09.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Nora Patel</div><div class="cf-post-meta"><span>47 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer9"><![CDATA[]]></res>
  <res label="copy10">Found a quieter route along the river. A little longer, a lot nicer. This might become the regular Sunday ride.</res>
  <res label="byline10"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-10.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Luca Reed</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer10"><![CDATA[]]></res>
  <res label="copy11">No alarm, no rush, and the good mug. Keeping Saturday morning exactly like this for as long as possible.</res>
  <res label="byline11"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-01.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Maya Bennett</div><div class="cf-post-meta"><span>31 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer11"><![CDATA[]]></res>
  <res label="copy12">The weather forecast said cloudy. I’m very happy it was wrong. Even remembered to pack enough snacks this time.</res>
  <res label="byline12"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-02.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Ben Carter</div><div class="cf-post-meta"><span>5 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer12"><![CDATA[]]></res>
  <res label="copy13">The neighborhood is looking especially good this week. Whoever planted all these flowers deserves a thank-you.</res>
  <res label="byline13"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-03.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Elena Morris</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer13"><![CDATA[]]></res>
  <res label="copy14">Went down to the harbor before everyone else woke up. Just the boats, the gulls and a very peaceful half hour.</res>
  <res label="byline14"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-04.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Sam Rivera</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer14"><![CDATA[]]></res>
  <res label="copy15">The basil has officially survived longer than any of my previous attempts. The secret seems to be not watering it every time I walk past.</res>
  <res label="byline15"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-05.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Priya Shah</div><div class="cf-post-meta"><span>3 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer15"><![CDATA[]]></res>
  <res label="copy16">Picked up a few books at the weekend swap. Came home with more than I brought, which probably defeats the point.</res>
  <res label="byline16"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-06.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Jordan Ellis</div><div class="cf-post-meta"><span>49 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer16"><![CDATA[]]></res>
  <res label="copy17">Cleared a corner of the table and got the paints out again. It’s been months. Forgot how quickly an afternoon disappears doing this.</res>
  <res label="byline17"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-07.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Theo Park</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer17"><![CDATA[]]></res>
  <res label="copy18">Everyone brought “just a little something” for lunch. We could have fed the entire park.</res>
  <res label="byline18"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-08.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Amara Brooks</div><div class="cf-post-meta"><span>3 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer18"><![CDATA[]]></res>
  <res label="copy19">Made a loaf for a neighbor and then had to make another one because the house smelled too good to give it all away.</res>
  <res label="byline19"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-09.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Nora Patel</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer19"><![CDATA[]]></res>
  <res label="copy20">First ride after finally fixing that squeaky brake. Amazing how much more peaceful cycling is without a soundtrack.</res>
  <res label="byline20"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-10.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Luca Reed</div><div class="cf-post-meta"><span>42 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer20"><![CDATA[]]></res>
  <res label="copy21">A small victory: got up early enough to read a chapter before the day started. Might even try it again tomorrow.</res>
  <res label="byline21"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-01.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Maya Bennett</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer21"><![CDATA[]]></res>
  <res label="copy22">Still finding sand in my shoes from this walk. No complaints. Already planning the next one.</res>
  <res label="byline22"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-02.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Ben Carter</div><div class="cf-post-meta"><span>6 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer22"><![CDATA[]]></res>
  <res label="copy23">Walked to the local bakery instead of driving. Took twice as long because I stopped to look at every garden along the way.</res>
  <res label="byline23"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-03.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Elena Morris</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer23"><![CDATA[]]></res>
  <res label="copy24">One last photo from our little coastal break. The kind of place where you immediately start talking about coming back.</res>
  <res label="byline24"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-04.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Sam Rivera</div><div class="cf-post-meta"><span>4 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer24"><![CDATA[]]></res>
  <res label="copy25">Fresh mint for tea, basil for dinner. Feeling ridiculously proud of these little pots.</res>
  <res label="byline25"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-05.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Priya Shah</div><div class="cf-post-meta"><span>35 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer25"><![CDATA[]]></res>
  <res label="copy26">Put my phone in the other room and actually read for an hour. Leaving this here as a reminder to do that more often.</res>
  <res label="byline26"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-06.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Jordan Ellis</div><div class="cf-post-meta"><span>3 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer26"><![CDATA[]]></res>
  <res label="copy27">The table is a mess and there’s paint on my sleeve, but I’m pretty pleased with how this one is coming along.</res>
  <res label="byline27"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-07.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Theo Park</div><div class="cf-post-meta"><span>58 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer27"><![CDATA[]]></res>
  <res label="copy28">Last-minute picnic before the weather turns. Bread, cheese, pears. Sometimes the simple plan is the best one.</res>
  <res label="byline28"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-08.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Amara Brooks</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer28"><![CDATA[]]></res>
  <res label="copy29">Tried the overnight dough recipe everyone keeps recommending. Very little effort, very good toast. This one’s staying in the rotation.</res>
  <res label="byline29"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-09.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Nora Patel</div><div class="cf-post-meta"><span>5 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer29"><![CDATA[]]></res>
  <res label="copy30">Stopped here for five minutes and somehow stayed for twenty. Hard to hurry when the river looks like this.</res>
  <res label="byline30"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-10.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Luca Reed</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer30"><![CDATA[]]></res>

3. Define sponsored offers and all sixteen post images

Replace the entire BUILD: FEED_ADS_IMAGES comment line in the XML scaffold with this block.

Copy levels 31–42 supply the fictional sponsored content. Their bylines use brand initials and brand-specific classes instead of personal avatars, and their metadata labels them Sponsored. Their offerN resources contain a display domain, headline and offer detail. The .example domains are demonstration text, not tracking or checkout endpoints.

image1–image16 each define a post photograph with meaningful alt text, an 800×600 reserved size and async decoding. A design record's image level chooses one of these resources independently of its copy level. The source stays in data-src until the enhanced card is built. Copy all resources: a different assigned version can reference content you do not see in your first preview.

  <res label="copy31">Your laptop, water bottle, lunch—and room for the weekend. Meet our 18L Everyday Pack. $59, with free shipping this week.</res>
  <res label="byline31"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-1" aria-hidden="true">AT</span><div class="cf-author-details"><div class="cf-source">Aster Trail</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer31"><![CDATA[<div class="cf-offer"><div class="cf-domain">astertrail.example</div><div class="cf-offer-title">One pack. Every kind of day.</div><div class="cf-offer-detail">$59 · Free shipping</div></div>]]></res>
  <res label="copy32">Workday essentials. Weekend plans. Our Everyday Pack keeps both organized, with a padded laptop sleeve and easy-access bottle pockets. Now $59.</res>
  <res label="byline32"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-1" aria-hidden="true">AT</span><div class="cf-author-details"><div class="cf-source">Aster Trail</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer32"><![CDATA[<div class="cf-offer"><div class="cf-domain">astertrail.example</div><div class="cf-offer-title">The 18L Everyday Pack</div><div class="cf-offer-detail">$59 · 3 colors</div></div>]]></res>
  <res label="copy33">Take the scenic route. A comfortable everyday pack for the commute, the trail and the coffee stop in between. Get 15% off your first order with FIRST15.</res>
  <res label="byline33"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-1" aria-hidden="true">AT</span><div class="cf-author-details"><div class="cf-source">Aster Trail</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer33"><![CDATA[<div class="cf-offer"><div class="cf-domain">astertrail.example</div><div class="cf-offer-title">Pack light. Go a little further.</div><div class="cf-offer-detail">15% off your first order</div></div>]]></res>
  <res label="copy34">A place for everything you actually carry. Discover the 18L Everyday Pack in forest, slate and sand. Free delivery on orders over $50.</res>
  <res label="byline34"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-1" aria-hidden="true">AT</span><div class="cf-author-details"><div class="cf-source">Aster Trail</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer34"><![CDATA[<div class="cf-offer"><div class="cf-domain">astertrail.example</div><div class="cf-offer-title">Made for your everyday</div><div class="cf-offer-detail">From $59 · Free delivery over $50</div></div>]]></res>
  <res label="copy35">Good mornings start here. Our smooth House Blend brings notes of chocolate and toasted nuts to your favorite mug. Try a 250g bag for $14.</res>
  <res label="byline35"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-2" aria-hidden="true">K&amp;K</span><div class="cf-author-details"><div class="cf-source">Kettle &amp; Kind</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer35"><![CDATA[<div class="cf-offer"><div class="cf-domain">kettleandkind.example</div><div class="cf-offer-title">Meet your new morning coffee</div><div class="cf-offer-detail">House Blend · $14 / 250g</div></div>]]></res>
  <res label="copy36">Find your favorite cup. Try two of our most-loved blends in the Morning Duo, now $24. Whole bean or ground—your call.</res>
  <res label="byline36"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-2" aria-hidden="true">K&amp;K</span><div class="cf-author-details"><div class="cf-source">Kettle &amp; Kind</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer36"><![CDATA[<div class="cf-offer"><div class="cf-domain">kettleandkind.example</div><div class="cf-offer-title">Two blends. One better morning.</div><div class="cf-offer-detail">Morning Duo · $24</div></div>]]></res>
  <res label="copy37">Running low on the good coffee? Take 20% off your first coffee order with HELLO20. Pick your blend, choose your grind, put the kettle on.</res>
  <res label="byline37"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-2" aria-hidden="true">K&amp;K</span><div class="cf-author-details"><div class="cf-source">Kettle &amp; Kind</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer37"><![CDATA[<div class="cf-offer"><div class="cf-domain">kettleandkind.example</div><div class="cf-offer-title">A fresh start for your coffee shelf</div><div class="cf-offer-detail">20% off first order</div></div>]]></res>
  <res label="copy38">Coffee worth making time for. Discover our House Blend and Weekend Roast. Free shipping when you choose any three bags.</res>
  <res label="byline38"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-2" aria-hidden="true">K&amp;K</span><div class="cf-author-details"><div class="cf-source">Kettle &amp; Kind</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer38"><![CDATA[<div class="cf-offer"><div class="cf-domain">kettleandkind.example</div><div class="cf-offer-title">Your next favorite cup</div><div class="cf-offer-detail">Free shipping on 3 bags</div></div>]]></res>
  <res label="copy39">A little green goes a long way. Our ceramic windowsill planters have a drainage hole and matching saucer. Starting at $24. Plant not included.</res>
  <res label="byline39"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-3" aria-hidden="true">L</span><div class="cf-author-details"><div class="cf-source">Leafline Studio</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer39"><![CDATA[<div class="cf-offer"><div class="cf-domain">leaflinestudio.example</div><div class="cf-offer-title">Small pots. Happier corners.</div><div class="cf-offer-detail">Ceramic planters · From $24</div></div>]]></res>
  <res label="copy40">Give your favorite plant a fresh home. Meet the Everyday Planter in sage, cream and terracotta. Buy two and save 15%. Plants not included.</res>
  <res label="byline40"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-3" aria-hidden="true">L</span><div class="cf-author-details"><div class="cf-source">Leafline Studio</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer40"><![CDATA[<div class="cf-offer"><div class="cf-domain">leaflinestudio.example</div><div class="cf-offer-title">Room to grow</div><div class="cf-offer-detail">Save 15% when you buy 2</div></div>]]></res>
  <res label="copy41">That sunny corner is missing something. Add a ceramic planter in a color that feels like home. Free shipping on orders over $45.</res>
  <res label="byline41"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-3" aria-hidden="true">L</span><div class="cf-author-details"><div class="cf-source">Leafline Studio</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer41"><![CDATA[<div class="cf-offer"><div class="cf-domain">leaflinestudio.example</div><div class="cf-offer-title">Find your windowsill favorite</div><div class="cf-offer-detail">From $24 · Free shipping over $45</div></div>]]></res>
  <res label="copy42">Simple shapes. Soft colors. A proper drainage hole. Discover our Everyday Planter collection and take 10% off your first order with GROW10.</res>
  <res label="byline42"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-3" aria-hidden="true">L</span><div class="cf-author-details"><div class="cf-source">Leafline Studio</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer42"><![CDATA[<div class="cf-offer"><div class="cf-domain">leaflinestudio.example</div><div class="cf-offer-title">A fresh home for your plants</div><div class="cf-offer-detail">10% off your first order</div></div>]]></res>
  <res label="image1"><![CDATA[<img data-src="[rel image-01.jpg]" alt="Coffee, a croissant and an open book on a kitchen table" width="800" height="600" decoding="async"/>]]></res>
  <res label="image2"><![CDATA[<img data-src="[rel image-02.jpg]" alt="A coastal walking path above the sea" width="800" height="600" decoding="async"/>]]></res>
  <res label="image3"><![CDATA[<img data-src="[rel image-03.jpg]" alt="Colorful front doors and gardens on a quiet street" width="800" height="600" decoding="async"/>]]></res>
  <res label="image4"><![CDATA[<img data-src="[rel image-04.jpg]" alt="Small boats in a harbor at low tide" width="800" height="600" decoding="async"/>]]></res>
  <res label="image5"><![CDATA[<img data-src="[rel image-05.jpg]" alt="Basil and mint growing on a kitchen windowsill" width="800" height="600" decoding="async"/>]]></res>
  <res label="image6"><![CDATA[<img data-src="[rel image-06.jpg]" alt="Paperbacks and a cup of tea on a sofa" width="800" height="600" decoding="async"/>]]></res>
  <res label="image7"><![CDATA[<img data-src="[rel image-07.jpg]" alt="A watercolor painting in progress on a dining table" width="800" height="600" decoding="async"/>]]></res>
  <res label="image8"><![CDATA[<img data-src="[rel image-08.jpg]" alt="Bread, cheese and pears at a picnic in the park" width="800" height="600" decoding="async"/>]]></res>
  <res label="image9"><![CDATA[<img data-src="[rel image-09.jpg]" alt="A freshly baked loaf on a wooden kitchen board" width="800" height="600" decoding="async"/>]]></res>
  <res label="image10"><![CDATA[<img data-src="[rel image-10.jpg]" alt="A bicycle beside a leafy riverside path" width="800" height="600" decoding="async"/>]]></res>
  <res label="image11"><![CDATA[<img data-src="[rel image-11.jpg]" alt="A forest-green everyday backpack on a trail-side bench" width="800" height="600" decoding="async"/>]]></res>
  <res label="image12"><![CDATA[<img data-src="[rel image-12.jpg]" alt="A slate everyday backpack with daily essentials" width="800" height="600" decoding="async"/>]]></res>
  <res label="image13"><![CDATA[<img data-src="[rel image-13.jpg]" alt="A bag of coffee and a freshly poured cup on a counter" width="800" height="600" decoding="async"/>]]></res>
  <res label="image14"><![CDATA[<img data-src="[rel image-14.jpg]" alt="Coffee beans, a pour-over brewer and a ceramic mug" width="800" height="600" decoding="async"/>]]></res>
  <res label="image15"><![CDATA[<img data-src="[rel image-15.jpg]" alt="Sage and cream ceramic planters with houseplants" width="800" height="600" decoding="async"/>]]></res>
  <res label="image16"><![CDATA[<img data-src="[rel image-16.jpg]" alt="Terracotta and sage planters in a sunny home" width="800" height="600" decoding="async"/>]]></res>

4. Persist assignment and measurement revisions

Replace the entire BUILD: FEED_ASSIGNMENT comment line in the XML scaffold with this block.

Assign DesignVersion from 1–8 only when absent. Record DesignRevision=5 and ExposureRevision=1 to distinguish the content design from the full-card timing definition. SessionKey provides a response-specific browser cache namespace and is likewise assigned only when absent.

The initialization HTML explains the activity and shows a loading skeleton. Its <suspend /> creates a page that the script advances using the native Continue button, saving assignment before feed one. The supplied social-feed root does not set autosave; keep the initialization submission and test resume behavior in your account. Random version assignment in this synthetic example is not a quota-balanced or optimized experimental design.

  <number label="DesignVersion" where="execute" size="3">
    <title>Assigned .dat design version</title>
    <exec>
if DesignVersion.val is None:
    DesignVersion.val = random.randint(1,8)
</exec>
  </number>
  <number label="DesignRevision" where="execute" size="2">
    <title>Design and timing schema revision</title>
    <exec>DesignRevision.val = 5</exec>
  </number>
  <number label="ExposureRevision" where="execute" size="2">
    <title>Full-card exposure schema revision</title>
    <exec>ExposureRevision.val = 1</exec>
  </number>
  <number label="SessionKey" where="execute" size="12">
    <title>Anonymous response cache key</title>
    <exec>
if SessionKey.val is None:
    SessionKey.val = random.randint(100000000,999999999)
</exec>
  </number>
  <html label="Initialize" where="survey"><![CDATA[<div class="cf-init" role="status"><div class="cf-round">Feed 1 of 5</div><h2>Like the posts that stand out to you</h2><p>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</p><div class="cf-skeleton" aria-label="Preparing feed"></div></div>]]></html>
  <suspend />

5. Record the first feed’s twenty assignments

Replace the entire BUILD: FEED_ONE_OFFERS comment line in the XML scaffold with this block.

Offer1 is a server-only number matrix with one row per display position. The nine columns retain task plus the eight design attributes. In its <exec>, range(1,21) visits positions 1–20, looks up the version/task/position tuple and selects row i-1 because the Python row list starts at zero.

Every assignment writes all nine fields. task is 1 here; item/order identify placement, copy/image identify resources, kind identifies organic versus sponsored, and creative/campaign/context support analysis. These records let you join a response or timing cell back to the actual assigned content, even when the participant never Likes that post.

  <number label="Offer1" where="execute" optional="1" size="6">
    <title>Feed 1: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,1,i)]
    r = Offer1.rows[i-1]
    r.task.val = 1
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>

6. Create the five timing cells for each post

Replace the entire BUILD: FEED_ONE_TIME comment line in the XML scaffold with this block.

Time1 also has twenty rows, in the same position order. It intentionally remains a rendered native number matrix: JavaScript needs its inputs to write measurements before submission. cf-timing locates it, and the enhancement hides it only after discovery succeeds.

ms and state are the legacy duration and measurement state. anyms and halfms store cumulative time with at least 1% and 50% of the full card visible; exposurestate describes that full-card measurement. Initialization changes only empty cells: durations start at -1 for not yet instrumented, states at 0. Keeping that distinction prevents an uninitialized field from being reported as an observed zero.

  <number label="Time1" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time1.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>

7. Create the metadata and native Like matrix

Replace the entire BUILD: FEED_ONE_QUESTION comment line in the XML scaffold with this block.

Header1 emits .cf-config with revision, feed number, total feeds, version and session. The script reads those attributes to associate the correct page and cache. Feed1 is a required twenty-row radio matrix; cf-feed locates it and ss:accordionDisplay="0" retains the table presentation the mapper expects.

Its <exec> visits each design position and replaces the native row text with byline, caption, image and offer HTML from res[...]. %d inserts a resource number and %s inserts resource text. This Python is outside CDATA, so its literal HTML brackets are written as &lt; and &gt; for XML parsing.

Each post has columns c1/c2/c3 with export values 1/2/3. They mean not currently liked with no positive legacy qualifying time, not currently liked with positive legacy time, and currently liked. The browser defaults unanswered rows to c1, so zero Likes is valid despite the required matrix. The final page break submits this feed before the next one.

  <html label="Header1" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="1" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed1"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 1 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,1,i)]
    Feed1.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />

8. Add feed 2 with its own native fields

Replace the entire BUILD: FEED_2_PAGE comment line in the XML scaffold with this block.

This is the complete next page: Offer2, Time2, Header2, Feed2 and its <suspend />. It repeats the structure just explained with task 2 in the design lookup and field labels. Its twenty rows are positions within feed 2, not extra rows in feed one.

The offer execution records task 2; timing initialization preserves any existing measurements; configuration identifies feed 2 of five; the radio execution resolves that task's resources. Copy this whole block into its own marker. Keeping each page's four elements together gives the shared browser script exactly one feed matrix and one timing matrix to discover. No manual label substitution is needed.

  <number label="Offer2" where="execute" optional="1" size="6">
    <title>Feed 2: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,2,i)]
    r = Offer2.rows[i-1]
    r.task.val = 2
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>
  <number label="Time2" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time2.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>
  <html label="Header2" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="2" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed2"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 2 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,2,i)]
    Feed2.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />

9. Add feed 3 with its own native fields

Replace the entire BUILD: FEED_3_PAGE comment line in the XML scaffold with this block.

This is the complete next page: Offer3, Time3, Header3, Feed3 and its <suspend />. It repeats the structure just explained with task 3 in the design lookup and field labels. Its twenty rows are positions within feed 3, not extra rows in feed one.

The offer execution records task 3; timing initialization preserves any existing measurements; configuration identifies feed 3 of five; the radio execution resolves that task's resources. Copy this whole block into its own marker. Keeping each page's four elements together gives the shared browser script exactly one feed matrix and one timing matrix to discover. No manual label substitution is needed.

  <number label="Offer3" where="execute" optional="1" size="6">
    <title>Feed 3: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,3,i)]
    r = Offer3.rows[i-1]
    r.task.val = 3
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>
  <number label="Time3" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time3.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>
  <html label="Header3" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="3" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed3"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 3 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,3,i)]
    Feed3.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />

10. Add feed 4 with its own native fields

Replace the entire BUILD: FEED_4_PAGE comment line in the XML scaffold with this block.

This is the complete next page: Offer4, Time4, Header4, Feed4 and its <suspend />. It repeats the structure just explained with task 4 in the design lookup and field labels. Its twenty rows are positions within feed 4, not extra rows in feed one.

The offer execution records task 4; timing initialization preserves any existing measurements; configuration identifies feed 4 of five; the radio execution resolves that task's resources. Copy this whole block into its own marker. Keeping each page's four elements together gives the shared browser script exactly one feed matrix and one timing matrix to discover. No manual label substitution is needed.

  <number label="Offer4" where="execute" optional="1" size="6">
    <title>Feed 4: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,4,i)]
    r = Offer4.rows[i-1]
    r.task.val = 4
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>
  <number label="Time4" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time4.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>
  <html label="Header4" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="4" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed4"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 4 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,4,i)]
    Feed4.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />

11. Add feed 5 with its own native fields

Replace the entire BUILD: FEED_5_PAGE comment line in the XML scaffold with this block.

This is the complete next page: Offer5, Time5, Header5, Feed5 and its <suspend />. It repeats the structure just explained with task 5 in the design lookup and field labels. Its twenty rows are positions within feed 5, not extra rows in feed one.

The offer execution records task 5; timing initialization preserves any existing measurements; configuration identifies feed 5 of five; the radio execution resolves that task's resources. Copy this whole block into its own marker. Keeping each page's four elements together gives the shared browser script exactly one feed matrix and one timing matrix to discover. No manual label substitution is needed.

  <number label="Offer5" where="execute" optional="1" size="6">
    <title>Feed 5: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,5,i)]
    r = Offer5.rows[i-1]
    r.task.val = 5
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>
  <number label="Time5" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time5.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>
  <html label="Header5" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="5" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed5"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 5 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,5,i)]
    Feed5.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />

Replace the entire BUILD: FEED_FOOTER comment line in the XML scaffold with this block.

The default sample source is list zero, with messages for an already-completed response and a qualified completion. The empty survey.completion override and appended survey.respview.footer retain the source's final-page presentation. The long Base64 data URL is the encoded Questra SVG logo; it is image data rather than survey logic and needs no additional upload. The surrounding theme comments are only labels.

  <samplesources default="0">
    <samplesource list="0">
      <title>Open survey</title>
      <completed>You have already completed this study.</completed>
      <exit cond="qualified">Your responses have been recorded.</exit>
    </samplesource>
  </samplesources>
  <!-- questra-theme:start -->
  <style name="survey.completion"><![CDATA[]]></style>
  <style name="survey.respview.footer" mode="after"><![CDATA[<footer class="qt-footer"><img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjAwIiBoZWlnaHQ9IjQ4MCIgdmlld0JveD0iMCAwIDE2MDAgNDgwIj48cGF0aCBkPSJNMTE1Ni4wNSwzMDAuNDFjLTM0LjgyLDQwLjQtNzIuNzUsNzIuNjYtMTE1LjM4LDk4LjU0LTg2Ljk0LDUyLjc3LTE5My42OCw3OC40Mi0zMjYuMTcsNzguNDJzLTIzOS4yOC0yNS42NS0zMjYuMjItNzguNDJjLTQ0LjQtMjYuOTQtODMuNjYtNjAuNzMtMTE5LjY4LTEwMy41MywxNC4yNS00LjkzLDI3LjMyLTExLjk2LDM4Ljg1LTIwLjc5LDc3LjM4LDg4LjQyLDE5NS4zMywxNTkuNTgsNDA3LjA1LDE1OS41OCwxOTYuOTUsMCwzMTIuNzgtNjEuNiwzOTAuMjMtMTQxLjM3LDExLjExLDUuMzUsMjQuMzIsOC4yNywzOS4xLDguMjcsNC4yMSwwLDguMjktLjIzLDEyLjIxLS43WiIgZmlsbD0iIzEwMzc0MyIvPjxwYXRoIGQ9Ik0zOTIuNDMsMjA2LjY1Vjc4LjQyaDQ0LjE5djExNS4yMWMwLDI4LjgsMTguNTQsNDguMTQsNDYuOTUsNDguMTQsMjkuOTksMCw1MC4xMS0xOS43Myw1MC4xMS00OC45M3YtMTE0LjQyaDQ0LjE5djE0MC4wN2MwLDExLjQ0LDcuMSwxOC41NCwxOC41NCwxOC41NGgzLjk0djQyLjYxaC0xMy4wMmMtMjYuNDMsMC00My40LTEwLjI2LTUwLjExLTI5LjItMTUuMzksMjIuMS0zOC42NywzMy45My02Ny44NywzMy45My00Ni4xNiwwLTc2Ljk0LTMwLjc4LTc2Ljk0LTc3LjczWiIgZmlsbD0iIzEwMzc0MyIvPjxwYXRoIGQ9Ik02MTguMjIsMTc5LjAzYzAtNTkuOTcsNDYuMTYtMTA1LjM1LDEwNy4zMy0xMDUuMzVzMTA3LjcyLDQ1LjM4LDEwNy43MiwxMDUuNzVjMCw1LjUyLS40LDExLjQ0LTEuMTksMTYuNTdoLTE2Ni41MWM2LjcxLDI5LjIsMzAuMzgsNDguNTMsNjEuOTUsNDguNTMsMjMuMjgsMCw0My40LTEwLjI2LDUzLjY2LTI1LjY1aDQ4LjkzYy0xNi4xOCwzOS4wNi01NS42Myw2NS41LTEwMy4zOCw2NS41LTYyLjM0LDAtMTA4LjUxLTQ1LjM3LTEwOC41MS0xMDUuMzVaTTY2NS45NiwxNTkuN2gxMTkuOTVjLTYuNzEtMjcuNjItMzAuMzgtNDYuMTYtNjAuMzctNDYuMTZzLTUyLjQ4LDE4LjE1LTU5LjU4LDQ2LjE2WiIgZmlsbD0iIzEwMzc0MyIvPjxwYXRoIGQ9Ik04NjAuMDYsMjIwLjQ2aDQ0Ljk4YzAsMTUuMzksMTQuNiwyNS42NSwzNS45MSwyNS42NSwxOS43MywwLDMyLjc0LTkuMDgsMzIuNzQtMjEuNywwLTM2LjMtMTEwLjQ3LTE2LjE4LTExMC40Ny04Ny41OSwwLTM5LjA2LDMxLjE3LTYzLjEzLDc1Ljc2LTYzLjEzczc2LjU1LDI0Ljg2LDc2LjU1LDYxLjE2aC00NC45OGMwLTEzLjgxLTEzLjAyLTIzLjI4LTMxLjk2LTIzLjI4cy0zMC43Nyw4LjI5LTMwLjc3LDIwLjUyYzAsMzUuMTEsMTEwLjg3LDE1Ljc4LDExMC44Nyw4Ny41OSwwLDM5LjA2LTMxLjE3LDY0LjcxLTc4LjEyLDY0Ljcxcy04MC40OS0yNi4wNC04MC40OS02My45MloiIGZpbGw9IiMxMDM3NDMiLz48cGF0aCBkPSJNMTIzOC41Nyw3OC40Mmg0NC4xOXYzMy41NGMxNS43OS0yMi44OCwzOS4wNi0zNi42OSw2Ny40Ny0zNi42OWg3LjF2NDUuMzdoLTcuMWMtNDIuNjIsMC02Ny40NywyNC4wNy02Ny40Nyw2MS4xNnY5Ny44NWgtNDQuMTlWNzguNDJaIiBmaWxsPSIjMTAzNzQzIi8+PHBhdGggZD0iTTEzNjQuMDUsMTc5LjAzYzAtNTkuOTcsNDIuMjItMTA1LjM1LDk5LjAzLTEwNS4zNSwyOS42LDAsNTQuMDYsMTIuNjMsNzAuNjMsMzMuNTR2LTI4LjhoNDQuMTl2MTQwLjA3YzAsMTEuNDQsNi43MSwxOC41NCwxOC41NCwxOC41NGgzLjU1djQyLjYxaC0xMi42M2MtMjcuNjIsMC00NC45OC0xMS4wNS01MC45LTMxLjk2LTE2Ljk3LDIyLjg5LTQyLjYyLDM2LjctNzMuNCwzNi43LTU2LjgxLDAtOTkuMDMtNDUuMzctOTkuMDMtMTA1LjM1Wk0xNTMzLjcxLDE3OS4wM2MwLTM1LjUxLTI2LjQzLTYyLjc0LTYxLjk0LTYyLjc0cy02Mi4zNCwyNy4yMi02Mi4zNCw2Mi43NCwyNi40NCw2Mi43NCw2Mi4zNCw2Mi43NCw2MS45NC0yNy4yMiw2MS45NC02Mi43NFoiIGZpbGw9IiMxMDM3NDMiLz48cGF0aCBkPSJNMTQ0LjI2LDgxLjg3Yy01Ljk4LDcuMzQtMTAuOTEsMTUuNi0xNC40MywyNC42Nkg0OS4zN3YtMjQuNjZoOTQuODlaIiBmaWxsPSIjZmY1MDVkIi8+PHJlY3QgeT0iODEuODUiIHdpZHRoPSIyNC42NyIgaGVpZ2h0PSIyNC42NyIgZmlsbD0iI2ZmNTA1ZCIvPjxwYXRoIGQ9Ik0xMjIuOTIsMTQzLjUyYzAsNC4xOS4yNSw4LjMyLjc0LDEyLjMzaC00OS42M3YtMjQuNjZoNDkuNjNjLS40OSw0LjAxLS43NCw4LjE0LS43NCwxMi4zM1oiIGZpbGw9IiNmZjUwNWQiLz48cGF0aCBkPSJNMTQ0LjI2LDIwNS4xOEg0OS4zN3YtMjQuNjZoODAuNDZjMy41MSw5LjA2LDguNDUsMTcuMzMsMTQuNDMsMjQuNjZaIiBmaWxsPSIjZmY1MDVkIi8+PHJlY3QgeD0iMjQuNjciIHk9IjEzMS4xOSIgd2lkdGg9IjI0LjY3IiBoZWlnaHQ9IjI0LjY3IiBmaWxsPSIjZmY1MDVkIi8+PHJlY3QgeT0iMTgwLjUzIiB3aWR0aD0iMjQuNjciIGhlaWdodD0iMjQuNjciIGZpbGw9IiNmZjUwNWQiLz48cGF0aCBkPSJNMTA3Ni43NSwyMjEuMjV2LTEwMi41OWgtMzMuOTN2LTQwLjI0aDIwLjUxYzEwLjI2LDAsMTUuNzktNS41MiwxNS43OS0xNS43OFYyMy45N2g0MS44MnY1NC40NWg2NS44OXY0MC4yNGgtNjUuODl2OTguMjVjMCwxMy40MSw5LjA4LDIyLjEsMjIuODksMjIuMXMyMi44OS05LjQ3LDIyLjg5LTI1LjI1aDM5LjQ2YzAsNDAuMjQtMjUuMjUsNjUuODktNjUuNSw2NS44OXMtNjMuOTItMjMuMjgtNjMuOTItNTguNFoiIGZpbGw9IiMxMDM3NDMiLz48cGF0aCBkPSJNMzYxLjA0LDE0Mi43MmMwLDgwLjA5LTYxLjU0LDE0MC4wMi0xNDMuMjMsMTQwLjAyLTQ2Ljk4LDAtODcuNDktMjAuMjktMTEzLjMyLTUyLjloNzEuNThjMTIuNDUsNS45MiwyNi42NCw5LjE4LDQxLjc0LDkuMTgsMS45OSwwLDMuOTYtLjA2LDUuOTEtLjE3LTcuMDgtMTAuNjctMTMuOTktMjEuNzItMjEuMDYtMzMuNjhsMzcuMTgtMjIuMDFjOC42NywxNC42NywxNy40OSwyOC43MSwyNy4yNCw0Mi44NiwyNy44Ni0xNi4yNyw0NS44Ny00Ni40NSw0NS44Ny04Mi41LDAtNTQuNDQtNDEuMDctOTUuNTEtOTUuMTQtOTUuNTEtMTUuMSwwLTI5LjI5LDMuMjctNDEuNzQsOS4xOWgtNzMuNjhDMTI4LjEsMjMuNDcsMTY5LjUzLDIuNjMsMjE3LjgxLDIuNjNjODEuNjksMCwxNDMuMjMsNjAsMTQzLjIzLDE0MC4wOVoiIGZpbGw9IiMxMDM3NDMiLz48L3N2Zz4=" data-brand-source="https://www.questra.ai/logo/primary/full-color.svg" alt="Questra" width="120" height="36" decoding="async" /></footer>]]></style>
  <!-- questra-theme:end -->

4. Fill the styling hook

Fill the named markers inside respview.client.css in the scaffold. CSS blocks replace comments between the inner HTML <style> tags. Where this example includes a head script, its marker is explicitly inside <script>.

1. Set the page colors, column and native fields

Replace the entire BUILD: THEME_PAGE comment line in the CSS hook’s inner <style> with this block.

The --qt-* custom properties name the palette, surface and radius so later rules can refer to them with var(...). color-scheme: light requests light browser controls. The HTML/body rules remove the default margin and set the background, text, font and minimum viewport height.

#survey becomes a centered, padded column, capped at 1240 pixels. The section/body and question selectors remove the default panels while keeping full available width. Question headings scale with clamp; instructions retain a generous line height. .answers permits horizontal overflow for a native matrix. Text controls inherit the font and receive padding and borders; radio/checkbox inputs receive an accent color and minimum dimensions. These rules style the native fallback as well as the finished activity.

      /* Questra brand: questra-workspace/brand/motion/motion.js, BRAND (lines 51–52).
         Shared shell and native controls only. No font or stylesheet network dependency. */
      :root {
        --qt-chalk: #f5f1ec;
        --qt-coral: #ff505d;
        --qt-slate: #103743;
        --qt-line: #10374333;
        --qt-surface: #fff;
        --qt-radius: 24px;
        color-scheme: light;
      }
      html {
        background: var(--qt-chalk);
      }
      html body,
      html body.survey-page {
        margin: 0;
        background: var(--qt-chalk);
        color: var(--qt-slate);
        font:
          16px/1.5 Arial,
          Helvetica,
          sans-serif;
        min-height: 100vh;
      }
      body #survey {
        box-sizing: border-box;
        width: 100%;
        max-width: 1240px;
        margin: 0 auto;
        padding: 28px 32px 48px;
        background: transparent;
        border: 0;
        box-shadow: none;
        border-radius: 0;
      }
      body .survey-section,
      body .survey-body {
        box-sizing: border-box;
        max-width: none;
        width: 100%;
        margin: 0;
        padding: 0;
        background: transparent;
        border: 0;
        box-shadow: none;
      }
      body .survey-header,
      body .survey-footer {
        background: transparent;
        color: var(--qt-slate);
      }
      body .question {
        box-sizing: border-box;
        margin: 24px 0;
        padding: 0;
        background: transparent;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        color: var(--qt-slate);
      }
      body .question-text {
        font-size: clamp(22px, 3vw, 34px);
        line-height: 1.2;
        letter-spacing: -0.6px;
        color: var(--qt-slate);
      }
      body .instruction-text {
        color: var(--qt-slate);
        line-height: 1.6;
      }
      body .answers {
        max-width: 100%;
        overflow-x: auto;
      }
      body .answers input:not([type='radio']):not([type='checkbox']):not([type='hidden']),
      body .answers textarea,
      body .answers select {
        box-sizing: border-box;
        max-width: 100%;
        font: inherit;
        color: var(--qt-slate);
        background: white;
        border: 1px solid var(--qt-slate);
        border-radius: 8px;
        padding: 10px;
      }
      body input[type='radio'],
      body input[type='checkbox'] {
        accent-color: var(--qt-slate);
        min-width: 20px;
        min-height: 20px;
      }

Replace the entire BUILD: THEME_CONTROLS comment line in the CSS hook’s inner <style> with this block.

The button container wraps controls with a gap and aligns them to the right. Continue, Finish and Back share a minimum touch height, pill border and typeface; Back then overrides the fill and shadow. :focus-visible adds a keyboard outline. Error selectors preserve readable messages with a colored border. The example hides the progress bar. .qt-footer centers its image, and object-fit: contain keeps the logo's proportions. These declarations affect presentation, not answer selection or submission.

      body .survey-buttons {
        display: flex;
        flex-wrap: wrap;
        gap: 12px;
        justify-content: flex-end;
        padding: 24px 0;
      }
      body #btn_continue,
      body #btn_finish,
      body #btn_back {
        font:
          700 16px/1.4 Arial,
          sans-serif;
        min-height: 48px;
        padding: 13px 26px;
        border: 2px solid var(--qt-slate);
        border-radius: 999px;
        background: var(--qt-slate);
        color: var(--qt-chalk);
        cursor: pointer;
        box-shadow: 4px 4px 0 var(--qt-coral);
      }
      body #btn_back {
        background: transparent;
        color: var(--qt-slate);
        box-shadow: none;
      }
      body :focus-visible {
        outline: 3px solid var(--qt-slate);
        outline-offset: 4px;
      }
      body .survey-error,
      body .question-error,
      body .error-text {
        color: var(--qt-slate);
        background: var(--qt-chalk);
        border-left: 4px solid var(--qt-coral);
        padding: 12px;
      }
      body .progress-bar,
      body [role='progressbar'] {
        display: none !important;
      }
      .qt-footer {
        display: flex;
        justify-content: center;
        padding: 32px 20px 40px;
        background: transparent;
      }
      .qt-footer img {
        display: block;
        width: 120px;
        height: 36px;
        object-fit: contain;
      }

3. Give loading a deadline

Replace the entire BUILD: THEME_GATE_CSS comment line in the CSS hook’s inner <style> with this block.

While html has qt-pending, questions and the named custom interfaces are temporarily invisible. qt-reveal makes them visible after 1.8 seconds even if later JavaScript fails. The matching pseudo-element displays “Preparing your activity…” and qt-dismiss removes it at the same deadline. forwards retains the keyframe's ending state.

The 650-pixel media query reduces page spacing. The reduced-motion query prevents smooth page scrolling. These loading rules never hide the form, navigation or validation container itself.

      /* The optional early gate never hides the form, navigation or validation messages.
         CSS provides an independent fail-open deadline even if a later script throws. */
      html.qt-pending .question,
      html.qt-pending .outfit-ui,
      html.qt-pending .sh-ui {
        visibility: hidden;
        animation: qt-reveal 0s 1.8s forwards;
      }
      html.qt-pending .survey-body:before {
        content: 'Preparing your activity…';
        display: block;
        padding: 24px;
        border-left: 4px solid var(--qt-coral);
        animation: qt-dismiss 0s 1.8s forwards;
      }
      \@keyframes qt-reveal {
        to {
          visibility: visible;
        }
      }
      \@keyframes qt-dismiss {
        to {
          display: none;
          visibility: hidden;
          height: 0;
          padding: 0;
        }
      }
      \@media (max-width: 650px) {
        body #survey {
          padding: 16px 12px 32px;
        }
        body .question {
          padding: 0;
          border-radius: 0;
          margin: 16px 0;
        }
      }
      \@media (prefers-reduced-motion: reduce) {
        body {
          scroll-behavior: auto;
        }
      }

4. Release the loading state

Replace the entire BUILD: THEME_GATE_JS comment line in the CSS hook’s existing <script> with this block.

This script is intentionally inside the CSS hook's HTML payload: it runs in the head, before the body is parsed. It adds qt-pending, then exposes two small methods as window.QuestraTheme. ready() reveals the page after setup; canEnhance() says whether the cosmetic loading window is still open.

reveal(true) also sets expired, so a late component does not replace controls after the respondent starts using them. The 1800-millisecond timer, first key press, first pointer press and restored-page event all trigger that fallback. once removes an interaction listener after its first call; capture lets it see the event early. The component's final ready() call releases the gate on a successful build.

      /* Runs inline in the head, before body parsing; no jQuery dependency. */
      (function () {
        'use strict';
        var root = document.documentElement;
        var expired = false;
        root.classList.add('qt-pending');
        function reveal(fallback) {
          if (fallback) expired = true;
          root.classList.remove('qt-pending');
        }
        window.QuestraTheme = {
          canEnhance: function () {
            return !expired;
          },
          ready: function () {
            reveal(false);
          }
        };
        setTimeout(function () {
          reveal(true);
        }, 1800);
        // Keyboard/pointer intent takes precedence over cosmetic loading.
        document.addEventListener(
          'keydown',
          function () {
            reveal(true);
          },
          { once: true, capture: true }
        );
        document.addEventListener(
          'pointerdown',
          function () {
            reveal(true);
          },
          { once: true, capture: true }
        );
        window.addEventListener('pageshow', function (event) {
          if (event.persisted) reveal(true);
        });
      })();

5. Set the feed width, native visibility and loading states

Replace the entire BUILD: FEED_PAGE comment line in the CSS hook’s inner <style> with this block.

The .question.cf-feed prefix scopes the feed. Heading/instruction/round styles establish its title and task indicator. .cf-native-hidden hides only the matrices after JavaScript adds that class, rather than hiding an unanswered native form in advance.

The media container reserves room for a picture. A missing source is hidden, and loading/failed attributes select an overlay message. .cf-skeleton supplies the placeholder appearance on the initialization page. .cf-init controls that page's width and type. These states communicate loading; they do not create exposure time.

      /* All presentation stays within this question or its initialization placeholder. */
      .question.cf-feed {
        color: #050505;
        font-family: Arial, Helvetica, sans-serif;
        -webkit-font-smoothing: antialiased;
      }
      .question.cf-feed .question-text,
      .question.cf-feed .instruction-text {
        max-width: 590px;
        margin-left: auto;
        margin-right: auto;
        box-sizing: border-box;
      }
      .question.cf-feed .question-text {
        font:
          600 17px/1.3 Arial,
          Helvetica,
          sans-serif;
        margin-bottom: 6px;
      }
      .question.cf-feed .instruction-text {
        font:
          14px/1.45 Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin-top: 0;
        margin-bottom: 16px;
      }
      .question.cf-feed .cf-round {
        display: block;
        font:
          12px/16px Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin-bottom: 8px;
      }
      .question.cf-timing.cf-native-hidden {
        display: none !important;
      }
      .question.cf-feed .cf-native-hidden {
        display: none !important;
      }
      .question.cf-feed .cf-art {
        aspect-ratio: 4/3;
      }
      .question.cf-feed .cf-art img:not([src]) {
        visibility: hidden;
      }
      .question.cf-feed .cf-art[data-failed]::after {
        content: 'Image unavailable';
        position: absolute;
        inset: 45% 0 auto;
        text-align: center;
        font:
          14px Arial,
          sans-serif;
        color: #65676b;
      }
      .question.cf-feed .cf-art[data-loading]::after {
        content: 'Loading image…';
        position: absolute;
        inset: 45% 0 auto;
        text-align: center;
        font:
          14px Arial,
          sans-serif;
        color: #65676b;
      }
      /* A still placeholder reserves the same local column before enhancement. */
      .cf-init .cf-skeleton {
        content: '';
        display: block;
        box-sizing: border-box;
        max-width: 590px;
        height: 560px;
        margin: 0 auto;
        border: 1px solid #e4e6eb;
        border-radius: 8px;
        background:
          linear-gradient(#e4e6eb, #e4e6eb) 16px 18px/40px 40px no-repeat,
          linear-gradient(#e4e6eb, #e4e6eb) 68px 23px/140px 12px no-repeat,
          linear-gradient(#eef0f2, #eef0f2) 68px 43px/86px 9px no-repeat,
          linear-gradient(#e4e6eb, #e4e6eb) 16px 82px/78% 12px no-repeat,
          linear-gradient(#eef0f2, #eef0f2) 16px 104px/56% 12px no-repeat,
          linear-gradient(#e4e6eb, #e4e6eb) 0 140px/100% 380px no-repeat,
          #fff;
      }
      .cf-init {
        max-width: 590px;
        margin: 0 auto;
        font-family: Arial, Helvetica, sans-serif;
        color: #050505;
      }
      .cf-init .cf-round {
        font:
          12px/16px Arial,
          sans-serif;
        color: #65676b;
        margin-bottom: 8px;
      }
      .cf-init h2 {
        font:
          600 17px/1.3 Arial,
          sans-serif;
        margin: 0 0 6px;
      }
      .cf-init p {
        font:
          14px/1.45 Arial,
          sans-serif;
        color: #65676b;
        margin: 0 0 16px;
      }

6. Style the stream, authors and captions

Replace the entire BUILD: FEED_CARDS comment line in the CSS hook’s inner <style> with this block.

The layout centers a readable stream. Instruction selectors style the reusable instruction treatment; each card has its own surface, border and spacing. The author row aligns avatar and details. Personal avatars crop to circles; brand avatars center initials on a brand-specific color.

Author name, timestamp and decorative metadata icon each get an appropriate size and spacing. Caption rules set padding, line height and wrapping. The resource HTML uses these exact class names, which is why byline resources and styles must remain coordinated.

      .question.cf-feed .cf-layout {
        max-width: 590px;
        margin: 0 auto;
        padding: 0;
        box-sizing: border-box;
        background: #f0f2f5;
      }
      .question.cf-feed .cf-instructions {
        margin-bottom: 16px;
        padding: 16px;
        background: white;
        border-radius: 8px;
        box-shadow: 0 1px 2px #00000020;
      }
      .question.cf-feed .cf-round {
        font-size: 12px;
        line-height: 16px;
        color: #65676b;
        margin-bottom: 8px;
      }
      .question.cf-feed .cf-instructions h2 {
        font:
          600 17px/1.3 Arial,
          Helvetica,
          sans-serif;
        margin: 0 0 6px;
        color: #050505;
      }
      .question.cf-feed .cf-instructions p {
        font:
          14px/1.45 Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin: 0;
      }
      .question.cf-feed .cf-card {
        background: #fff;
        border: 0;
        border-radius: 8px;
        overflow: hidden;
        margin: 0 0 16px;
        box-shadow: 0 1px 2px #00000026;
      }
      .question.cf-feed .cf-author-row {
        display: flex;
        align-items: center;
        gap: 9px;
        padding: 12px 16px 0;
      }
      .question.cf-feed .cf-avatar {
        display: block;
        flex: 0 0 40px;
        width: 40px;
        height: 40px;
        border-radius: 50%;
        object-fit: cover;
        box-shadow: inset 0 0 0 1px #0000000d;
      }
      .question.cf-feed .cf-brand-avatar {
        display: flex;
        align-items: center;
        justify-content: center;
        font:
          700 14px/1 Arial,
          Helvetica,
          sans-serif;
        letter-spacing: -0.5px;
      }
      .question.cf-feed .cf-brand-1 {
        background: #dfe9e1;
        color: #2b5039;
      }
      .question.cf-feed .cf-brand-2 {
        background: #eddfcc;
        color: #583b24;
      }
      .question.cf-feed .cf-brand-3 {
        background: #e5eadc;
        color: #50633d;
      }
      .question.cf-feed .cf-author-details {
        min-width: 0;
      }
      .question.cf-feed .cf-source {
        font:
          600 15px/20px Arial,
          Helvetica,
          sans-serif;
        color: #050505;
      }
      .question.cf-feed .cf-post-meta {
        display: flex;
        align-items: center;
        gap: 3px;
        font:
          12px/16px Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin-top: 1px;
      }
      .question.cf-feed .cf-post-meta svg {
        width: 12px;
        height: 12px;
      }
      .question.cf-feed .cf-copy {
        font:
          15px/1.42 Arial,
          Helvetica,
          sans-serif;
        padding: 12px 16px 14px;
        margin: 0 !important;
        color: #050505;
        white-space: pre-line;
        overflow-wrap: break-word;
      }

7. Fit post images, offer copy and Like controls

Replace the entire BUILD: FEED_MEDIA_LIKE comment line in the CSS hook’s inner <style> with this block.

The art container clips the reserved image area; its direct image fills the width with a consistent aspect and crop. Offer rules separate domain, headline and details below sponsored images.

The action row contains a button with visible text and SVG. Hover, active and focus-visible states provide feedback. [aria-pressed='true'] changes the Like color and fills its icon path; JavaScript sets that attribute from the native c3 selection. Styling the button as liked does not by itself select a native answer.

      .question.cf-feed .cf-art {
        position: relative;
        background: #e4e6eb;
        touch-action: pan-y;
        user-select: none;
        cursor: default;
      }
      .question.cf-feed .cf-art > img {
        display: block;
        width: 100%;
        height: auto;
        aspect-ratio: 4/3;
        object-fit: cover;
      }
      .question.cf-feed .cf-offer {
        background: #f0f2f5;
        border-bottom: 1px solid #dadde1;
        padding: 12px 16px;
      }
      .question.cf-feed .cf-domain {
        font:
          11px/16px Arial,
          Helvetica,
          sans-serif;
        text-transform: uppercase;
        letter-spacing: 0.25px;
        color: #65676b;
      }
      .question.cf-feed .cf-offer-title {
        font:
          600 16px/21px Arial,
          Helvetica,
          sans-serif;
        color: #050505;
        margin-top: 3px;
      }
      .question.cf-feed .cf-offer-detail {
        font:
          13px/18px Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin-top: 3px;
      }
      .question.cf-feed .cf-actions {
        margin: 0 16px;
        padding: 4px 0;
        display: flex;
        border-top: 1px solid #e4e6eb;
      }
      .question.cf-feed .cf-like {
        display: flex !important;
        align-items: center;
        justify-content: center;
        gap: 7px;
        width: 100%;
        border: 0 !important;
        background: transparent !important;
        color: #65676b !important;
        border-radius: 4px !important;
        padding: 9px 14px !important;
        font:
          600 14px/20px Arial,
          Helvetica,
          sans-serif !important;
        cursor: pointer;
        min-height: 40px;
        box-shadow: none !important;
        transition: background 0.12s;
      }
      .question.cf-feed .cf-like svg {
        width: 19px;
        height: 19px;
        flex: 0 0 19px;
      }
      .question.cf-feed .cf-like:hover {
        background: #f2f2f2 !important;
      }
      .question.cf-feed .cf-like[aria-pressed='true'] {
        color: #0866ff !important;
      }
      .question.cf-feed .cf-like[aria-pressed='true'] svg path {
        fill: #e7f0ff;
      }
      .question.cf-feed .cf-like:active {
        background: #e4e6eb !important;
      }
      .question.cf-feed .cf-like:focus-visible {
        outline: 3px solid #0866ff;
        outline-offset: 2px;
      }

8. Add the Like flash and responsive overrides

Replace the entire BUILD: FEED_ANIMATION comment line in the CSS hook’s inner <style> with this block.

An absolutely positioned, pointer-transparent icon provides a decorative flash over the image. Adding cf-liked-flash runs cf-pop, which scales and fades it. The small-screen query adjusts card/layout spacing and type. The reduced-motion query removes the animation/transition effects.

The final .cf-init .cf-round rule hides the initialization page's redundant round label. Keep it after the general round rules so that this specific override takes effect.

      .question.cf-feed .cf-like-flash {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 72px;
        height: 72px;
        margin: -36px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 50%;
        background: #0866ff;
        color: #fff;
        box-shadow: 0 3px 12px #0004;
        opacity: 0;
        pointer-events: none;
      }
      .question.cf-feed .cf-like-flash svg {
        width: 38px;
        height: 38px;
      }
      .question.cf-feed .cf-liked-flash .cf-like-flash {
        animation: cf-pop 0.65s ease-out both;
      }
      \@keyframes cf-pop {
        0% {
          opacity: 0;
          transform: scale(0.6);
        }
        20%,
        65% {
          opacity: 0.95;
          transform: scale(1);
        }
        100% {
          opacity: 0;
          transform: scale(1.08);
        }
      }
      \@media (max-width: 600px) {
        .question.cf-feed .cf-card {
          margin-bottom: 10px;
        }
        .question.cf-feed .cf-author-row,
        .question.cf-feed .cf-copy {
          padding-left: 12px;
          padding-right: 12px;
        }
        .question.cf-feed .cf-actions {
          margin: 0 12px;
        }
        .question.cf-feed .cf-offer {
          padding: 11px 12px;
        }
      }
      \@media (prefers-reduced-motion: reduce) {
        .question.cf-feed .cf-like {
          transition: none;
        }
        .question.cf-feed .cf-liked-flash .cf-like-flash {
          animation: none;
        }
      }
 
      .question.cf-feed .cf-round,
      .cf-init .cf-round {
        display: none;
      }

5. Fill the JavaScript hook

Fill the named markers inside respview.client.js. Keep the scaffold’s function openings, closing braces and ready wrapper. The sections share variables in those existing scopes; do not wrap each pasted section in a new function.

1. Define the legacy fraction and interval accumulator

Replace the entire BUILD: FEED_METER comment line in the JavaScript hook with this block.

These functions go inside the first, timing-library function. fraction() computes visible width and height clipped to the viewport. Its denominator caps card width and height at viewport dimensions, so this legacy fraction differs from the full-card fraction below. Empty areas return zero, and the result is capped at one.

meter() returns a stateful accumulator. It starts at a nonnegative total and remembers whether the previous sample qualified. Count a time difference only when both adjacent samples qualify and the interval is between 0 and 250 milliseconds. A longer qualifying gap is omitted and sets partial=true. Update the timestamp and eligibility on every sample, returning whole milliseconds. pause() clears the previous timestamp so a later visit cannot count the gap. state() returns 3 for incomplete, 2 for positive time or 1 for an instrumented zero.

      function fraction(rect, width, height) {
        const area = Math.min(rect.width, width) * Math.min(rect.height, height);
        if (!(area > 0)) return 0;
        const w = Math.max(0, Math.min(rect.right, width) - Math.max(rect.left, 0));
        const h = Math.max(0, Math.min(rect.bottom, height) - Math.max(rect.top, 0));
        return Math.min(1, (w * h) / area);
      }
      function meter(total = 0, partial = false) {
        return {
          total: Math.max(0, total),
          partial,
          last: null,
          eligible: false,
          sample(now, eligible) {
            if (this.last !== null) {
              const dt = now - this.last;
              if (this.eligible && eligible && dt >= 0 && dt <= 250) this.total += dt;
              else if (this.eligible && eligible && dt > 250) this.partial = true;
            }
            this.last = now;
            this.eligible = eligible;
            return Math.floor(this.total);
          },
          pause() {
            this.last = null;
            this.eligible = false;
          },
          state() {
            return this.partial ? 3 : this.total >= 1 ? 2 : 1;
          }
        };
      }

2. Measure visibility against the full card area

Replace the entire BUILD: FEED_FULL_FRACTION comment line in the JavaScript hook with this block.

fullFraction() starts with the card rectangle, then intersects it with every supplied clipping rectangle by taking the larger left/top and smaller right/bottom. Negative visible dimensions become zero. Divide that visible area by the full card width × height, with an early return for zero-sized cards.

The scaffold then exposes fraction, fullFraction and meter as one API. In Node's module environment it exports the API for deterministic tests; in the browser it assigns window.SocialFeedTiming. The typeof window check selects the available global object without assuming this is always a browser. This library does not find survey inputs or start a timer itself.

      // Full card denominator; clip rectangles represent viewport and overflow ancestors.
      function fullFraction(rect, clips) {
        if (!(rect.width > 0 && rect.height > 0)) return 0;
        let left = rect.left,
          right = rect.right,
          top = rect.top,
          bottom = rect.bottom;
        for (const clip of clips) {
          left = Math.max(left, clip.left);
          right = Math.min(right, clip.right);
          top = Math.max(top, clip.top);
          bottom = Math.min(bottom, clip.bottom);
        }
        return (
          (Math.max(0, right - left) * Math.max(0, bottom - top)) / (rect.width * rect.height)
        );
      }

3. Find corresponding Like and timing inputs

Replace the entire BUILD: FEED_DISCOVERY comment line in the JavaScript hook with this block.

The second function is the survey UI. Respect the theme gate; on the Initialize page, click native Continue and return. Otherwise find the feed root, native answers, form/Continue, page configuration and timing matrix. Stop if any are absent or the feed is already enhanced.

Group native radios by name. column() identifies a column by a header token suffix, not the HTML input's numeric value. Match each radio row with the corresponding numeric timing row and store all three Like inputs plus all five timing inputs. Optional chaining (?.) safely handles absent elements during discovery. Initialize per-row gesture timestamps to negative infinity so the first gesture is never suppressed. The final guard requires the entire mapping before proceeding.

      if (window.QuestraTheme && !window.QuestraTheme.canEnhance()) return;
      if (document.querySelector('#comment_Initialize')) {
        const start = document.querySelector('#btn_continue');
        if (start && !start.disabled) start.click();
        return;
      }
      const root = document.querySelector('.question.cf-feed');
      if (!root || root.dataset.enhanced) return;
      const native = root.querySelector('.answers'),
        form = root.closest('form'),
        next = form && form.querySelector('#btn_continue');
      const config = document.querySelector('.cf-config'),
        timing = document.querySelector('.question.cf-timing');
      if (!native || !next || !config || !timing) return;
      const groups = new Map();
      native.querySelectorAll('input[type=radio]').forEach(i => {
        if (!groups.has(i.name)) groups.set(i.name, []);
        groups.get(i.name).push(i);
      });
      function column(input, code) {
        return (input.closest('td')?.getAttribute('headers') || '')
          .split(/\s+/)
          .some(h => h.endsWith('_' + code));
      }
      const timeRows = Array.from(timing.querySelectorAll('tr')).filter(tr =>
        tr.querySelector('input[type=text],input[type=number]')
      );
      const rows = Array.from(groups.values()).map((inputs, index) => {
        const tr = inputs[0].closest('tr'),
          legend = tr && tr.querySelector('.row-legend'),
          codes = {};
        inputs.forEach(input =>
          ['c1', 'c2', 'c3'].forEach(code => {
            if (column(input, code)) codes[code] = input;
          })
        );
        const timeInputs = Array.from(timeRows[index]?.querySelectorAll('input') || []);
        return {
          inputs,
          legend,
          codes,
          ms: timeInputs.find(i => column(i, 'ms')),
          state: timeInputs.find(i => column(i, 'state')),
          anyms: timeInputs.find(i => column(i, 'anyms')),
          halfms: timeInputs.find(i => column(i, 'halfms')),
          exposurestate: timeInputs.find(i => column(i, 'exposurestate')),
          card: null,
          touch: null,
          lastGesture: -Infinity,
          lastButton: -Infinity
        };
      });
      if (
        !rows.length ||
        rows.some(
          r =>
            !r.legend ||
            Object.keys(r.codes).length !== 3 ||
            !r.ms ||
            !r.state ||
            !r.anyms ||
            !r.halfms ||
            !r.exposurestate
        )
      )
        return;
 

4. Scope the cache and detect measurement support

Replace the entire BUILD: FEED_RESTORE_SETUP comment line in the JavaScript hook with this block.

Read feed count/version and construct a key from survey path, session, feed and version. Measurement support requires the timing API, a monotonic performance.now clock, focus/visibility reporting and IntersectionObserver. Read only cache schema 6 with the expected row count; a parse/storage exception marks storage unavailable.

A reload or back/forward navigation with no usable cache sets lostCache, indicating potentially missing earlier time. gestureNow() has a wall-clock fallback for gesture deduplication. The flags distinguish submission and paused measurement, and lastSave throttles cache writes. selected() reads native columns with c1 as the initial default; choose() clicks the requested native input, redraws its Like control and saves.

      const feed = Number(config.dataset.feed),
        count = Number(config.dataset.feeds),
        version = config.dataset.version;
      const storageKey =
        'adfeed-exposure-v1:' +
        location.pathname +
        ':' +
        config.dataset.session +
        ':' +
        feed +
        ':' +
        version;
      const clock = window.SocialFeedTiming,
        supported = !!(
          clock &&
          window.performance &&
          typeof performance.now === 'function' &&
          typeof document.hasFocus === 'function' &&
          'visibilityState' in document &&
          typeof IntersectionObserver === 'function'
        );
      let restored = null,
        storageOK = true;
      try {
        const value = JSON.parse(sessionStorage.getItem(storageKey) || 'null');
        if (value && value.schema === 6 && value.items.length === rows.length)
          restored = value.items;
      } catch (e) {
        storageOK = false;
      }
      const navigation = window.performance?.getEntriesByType?.('navigation')[0]?.type;
      const gestureNow = () => (window.performance?.now ? performance.now() : Date.now());
      const lostCache =
        !restored && (navigation === 'reload' || navigation === 'back_forward');
      let submitting = false,
        paused = false,
        lastSave = 0;
      function selected(r) {
        return ['c1', 'c2', 'c3'].find(c => r.codes[c].checked) || 'c1';
      }
      function choose(r, c) {
        if (!r.codes[c].checked) r.codes[c].click();
        render(r);
        save();
      }

5. Write native timing cells and prepare the stream

Replace the entire BUILD: FEED_SAVE_RENDER comment line in the JavaScript hook with this block.

sync() exposes document state for inspection and copies whole-millisecond totals into native inputs. Unsupported measurement writes -1 durations and state 4. Legacy state comes from its meter; full-card state is 3 if either meter is incomplete, otherwise 2 for positive 1% time or 1 for zero.

save() synchronizes first, then stores schema 6 with each row's Like, totals and incompleteness flags. A storage failure marks all meters partial and synchronizes that warning back into native state fields. It never treats failed storage as complete measurement.

The inline thumb SVG draws the icon. render() reads whether native c3 is checked, updates aria-pressed and changes Like to Liked. Finally create the .cf-layout section and stream container, append it to the question, and retain the stream reference.

      function sync() {
        ui.dataset.pageVisible = document.visibilityState;
        ui.dataset.pageFocused = String(
          typeof document.hasFocus === 'function' && document.hasFocus()
        );
        rows.forEach(r => {
          r.ms.value = supported ? String(Math.floor(r.meter.total)) : '-1';
          r.state.value = supported ? String(r.meter.state()) : '4';
          r.anyms.value = supported ? String(Math.floor(r.anyMeter.total)) : '-1';
          r.halfms.value = supported ? String(Math.floor(r.halfMeter.total)) : '-1';
          r.exposurestate.value = supported
            ? String(
                r.anyMeter.partial || r.halfMeter.partial ? 3 : r.anyMeter.total >= 1 ? 2 : 1
              )
            : '4';
        });
      }
      function save() {
        sync();
        try {
          sessionStorage.setItem(
            storageKey,
            JSON.stringify({
              schema: 6,
              items: rows.map(r => ({
                like: selected(r),
                ms: r.meter.total,
                partial: r.meter.partial,
                anyms: r.anyMeter.total,
                halfms: r.halfMeter.total,
                exposurepartial: r.anyMeter.partial || r.halfMeter.partial
              }))
            })
          );
        } catch (e) {
          storageOK = false;
          rows.forEach(r => {
            r.meter.partial = true;
            r.anyMeter.partial = true;
            r.halfMeter.partial = true;
          });
          sync();
        }
      }
      const thumb =
        '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7.5 10.5v10H4a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h3.5Zm0 0L12 3c.4-.7 1.4-.7 1.8 0 .7 1.3.5 3.2-.1 5H19a2 2 0 0 1 2 2.4l-1.5 8.5a2 2 0 0 1-2 1.6h-10" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>';
      function render(r) {
        if (!r.card) return;
        const yes = selected(r) === 'c3',
          b = r.card.querySelector('.cf-like');
        b.setAttribute('aria-pressed', String(yes));
        b.innerHTML = thumb + '<span>' + (yes ? 'Liked' : 'Like') + '</span>';
      }
      const ui = document.createElement('section');
      ui.className = 'cf-layout';
      ui.innerHTML = '<div class="cf-stream"></div>';
      root.appendChild(ui);
      const stream = ui.querySelector('.cf-stream');

6. Restore each post and attach Like/image gestures

Replace the entire BUILD: FEED_BUILD comment line in the JavaScript hook with this block.

For each row, restore legacy time from a valid cache total or the native field. Restore each full-card total using the maximum of zero, native and cached values, never their sum. Carry incomplete flags forward, including lost cache or unavailable storage.

Create the card from the native row's resolved HTML and append a Like button. Assign image src from data-src; the first two cards load eagerly, later cards lazily, and the first card requests high fetch priority. Restore a cached Like or initialize an unanswered row to c1.

toggle() ignores submission and alternates c3 with c2 or c1 according to whether legacy time is positive. Button multi-clicks and image gestures are deduplicated with 420-millisecond guards. The image flash is restarted by removing its class, forcing layout and re-adding it. A successful image load marks the card rendered; an image error marks every meter incomplete and saves.

Desktop double-click calls the image gesture. Touch requires two pointer-up events within 340 milliseconds and 25 pixels; cancellation clears the pending tap. None of these Like actions adds milliseconds. After attaching the handlers, render the row's current Like state.

      rows.forEach((r, i) => {
        const cached = restored?.[i],
          nativeMs = Number(r.ms.value);
        const total =
          cached && Number.isFinite(cached.ms) && cached.ms >= 0
            ? cached.ms
            : Math.max(0, nativeMs || 0);
        r.meter = clock.meter(
          total,
          !!cached?.partial || !storageOK || lostCache || Number(r.state.value) === 3
        );
        const restoredTotal = key =>
          Math.max(0, Number(r[key].value) || 0, Number(cached?.[key]) || 0);
        const partial =
          !!cached?.exposurepartial ||
          !storageOK ||
          lostCache ||
          Number(r.exposurestate.value) === 3;
        r.anyMeter = clock.meter(restoredTotal('anyms'), partial);
        r.halfMeter = clock.meter(restoredTotal('halfms'), partial);
        const card = document.createElement('article');
        r.card = card;
        card.className = 'cf-card';
        card.dataset.item = String(i + 1);
        card.innerHTML =
          r.legend.innerHTML +
          '<div class="cf-actions"><button type="button" class="cf-like" aria-label="Like post ' +
          (i + 1) +
          '" aria-pressed="false">♡ Like</button></div>';
        stream.appendChild(card);
        card.querySelectorAll('img[data-src]').forEach(photo => {
          photo.loading = i < 2 ? 'eager' : 'lazy';
          photo.decoding = 'async';
          if (i === 0) photo.fetchPriority = 'high';
          photo.src = photo.dataset.src;
        });
        if (cached && ['c1', 'c2', 'c3'].includes(cached.like)) r.codes[cached.like].click();
        else if (!r.inputs.some(x => x.checked)) r.codes.c1.click();
        function toggle() {
          if (submitting) return;
          choose(r, selected(r) === 'c3' ? (r.meter.total >= 1 ? 'c2' : 'c1') : 'c3');
        }
        // A button click toggles immediately; subsequent click events in the same multi-click gesture do not.
        card.querySelector('.cf-like').addEventListener('click', e => {
          const now = gestureNow();
          if (e.detail > 1 && now - r.lastButton < 420) return;
          r.lastButton = now;
          toggle();
        });
        function imageGesture() {
          const now = gestureNow();
          if (now - r.lastGesture < 420) return;
          r.lastGesture = now;
          toggle();
          if (selected(r) === 'c3') {
            art.classList.remove('cf-liked-flash');
            void art.offsetWidth;
            art.classList.add('cf-liked-flash');
          }
        }
        const art = card.querySelector('.cf-art');
        if (art) {
          const flash = document.createElement('span');
          flash.className = 'cf-like-flash';
          flash.setAttribute('aria-hidden', 'true');
          flash.innerHTML = thumb;
          art.appendChild(flash);
          const photo = art.querySelector('img');
          art.dataset.loading = 'true';
          const loaded = () => {
            delete art.dataset.loading;
            r.rendered = !!(photo.complete && photo.naturalWidth > 0);
          };
          photo?.addEventListener('load', loaded);
          if (photo?.complete && photo.naturalWidth > 0) loaded();
          photo?.addEventListener('error', () => {
            delete art.dataset.loading;
            art.dataset.failed = 'true';
            r.rendered = false;
            r.meter.partial = true;
            r.anyMeter.partial = true;
            r.halfMeter.partial = true;
            save();
          });
          art.addEventListener('dblclick', e => {
            e.preventDefault();
            imageGesture();
          });
          art.addEventListener('pointerup', e => {
            if (e.pointerType !== 'touch') return;
            const now = gestureNow(),
              t = r.touch;
            if (
              t &&
              now - t.time < 340 &&
              Math.hypot(e.clientX - t.x, e.clientY - t.y) < 25
            ) {
              imageGesture();
              r.touch = null;
            } else r.touch = { time: now, x: e.clientX, y: e.clientY };
          });
          art.addEventListener('pointercancel', () => (r.touch = null));
        }
        render(r);
      });

7. Observe cards and sample the three visibility rules

Replace the entire BUILD: FEED_SAMPLE comment line in the JavaScript hook with this block.

The observer maps card elements back to rows and records whether they intersect. fullVisibleFraction() begins with the visual viewport, including its offsets, then walks ancestors. Any ancestor whose overflow clips an axis contributes its client rectangle on that axis; infinity leaves the other axis unclipped.

active() requires supported APIs, an unpaused/unsubmitted page, a visible document and browser focus. At each sample, the image must also have loaded successfully and enhancement must be active. The legacy meter additionally requires an observer intersection and at least half of the viewport-capped area. The two newer meters use the full-card fraction at 0.01 and 0.5 respectively.

All three meters receive the same timestamp. Once legacy time becomes positive, an unliked c1 row moves to c2; a current Like is retained. A tall card can accrue legacy time while never reaching 50% of its full area, so these duration columns are not interchangeable.

      const observed = new Map(rows.map(r => [r.card, r]));
      const observer = supported
        ? new IntersectionObserver(
            entries => {
              entries.forEach(entry => {
                const r = observed.get(entry.target);
                if (r) r.intersects = entry.isIntersecting;
              });
            },
            { threshold: 0 }
          )
        : null;
      if (observer) rows.forEach(r => observer.observe(r.card));
      function fullVisibleFraction(card) {
        const vv = window.visualViewport;
        const clips = [
          {
            left: vv ? vv.offsetLeft : 0,
            top: vv ? vv.offsetTop : 0,
            right: vv ? vv.offsetLeft + vv.width : innerWidth,
            bottom: vv ? vv.offsetTop + vv.height : innerHeight
          }
        ];
        for (let el = card.parentElement; el; el = el.parentElement) {
          const style = getComputedStyle(el),
            rect = el.getBoundingClientRect();
          const x = /(auto|scroll|hidden|clip)/.test(style.overflowX),
            y = /(auto|scroll|hidden|clip)/.test(style.overflowY);
          if (x || y)
            clips.push({
              left: x ? rect.left + el.clientLeft : -Infinity,
              right: x ? rect.left + el.clientLeft + el.clientWidth : Infinity,
              top: y ? rect.top + el.clientTop : -Infinity,
              bottom: y ? rect.top + el.clientTop + el.clientHeight : Infinity
            });
        }
        return clock.fullFraction(card.getBoundingClientRect(), clips);
      }
      function active() {
        return (
          supported &&
          !submitting &&
          !paused &&
          document.visibilityState === 'visible' &&
          document.hasFocus()
        );
      }
      function sample(now) {
        const enabled = active();
        rows.forEach(r => {
          const photo = r.card.querySelector('.cf-art img');
          const ready = photo && photo.complete && photo.naturalWidth > 0;
          const eligible =
            enabled &&
            root.dataset.enhanced === 'true' &&
            r.rendered &&
            ready &&
            r.intersects === true &&
            clock.fraction(r.card.getBoundingClientRect(), innerWidth, innerHeight) >= 0.5;
          r.meter.sample(now, eligible);
          const fraction =
            enabled && root.dataset.enhanced === 'true' && r.rendered && ready
              ? fullVisibleFraction(r.card)
              : 0;
          r.anyMeter.sample(now, fraction >= 0.01);
          r.halfMeter.sample(now, fraction >= 0.5);
          if (r.meter.total >= 1 && selected(r) === 'c1') {
            r.codes.c2.click();
            render(r);
          }
        });
      }

8. Flush, pause, resume and activate measurement

Replace the entire BUILD: FEED_LIFECYCLE comment line in the JavaScript hook with this block.

flush() takes a final sample if supported, then writes native inputs and cache. pause() flushes and clears every meter's previous timestamp. resume() also clears timestamps before taking a new sample, so time away from the page is excluded.

Capturing listeners flush before the native Continue and form-submit handlers read fields. Blur and hidden-document events pause; focus and visible-document events resume. Page hide pauses and marks submission; before-unload flushes; a page-cache restoration clears submission and resumes.

frame() uses requestAnimationFrame timestamps to sample and saves at most once per 250 milliseconds while active. Finally mark enhancement complete, hide native answer/timing presentation, save initialized measurements and start frames when supported. The scaffold closes the UI function and releases the theme gate. These are opportunity-to-see measures, not attention, reading or certified ad viewability: geometry does not detect covering overlays or other windows.

      function flush() {
        if (supported) sample(performance.now());
        save();
      }
      function pause() {
        flush();
        paused = true;
        rows.forEach(r => {
          r.meter.pause();
          r.anyMeter.pause();
          r.halfMeter.pause();
        });
      }
      function resume() {
        paused = false;
        rows.forEach(r => {
          r.meter.pause();
          r.anyMeter.pause();
          r.halfMeter.pause();
        });
        if (supported) sample(performance.now());
      }
      // Keep native navigation and validation intact. Save before native handlers read fields.
      next.addEventListener('click', flush, true);
      form.addEventListener('submit', flush, true);
      window.addEventListener('blur', pause);
      window.addEventListener('focus', resume);
      document.addEventListener('visibilitychange', () => {
        if (document.visibilityState === 'hidden') pause();
        else resume();
      });
      window.addEventListener('pagehide', () => {
        pause();
        submitting = true;
      });
      window.addEventListener('beforeunload', flush);
      window.addEventListener('pageshow', e => {
        if (e.persisted) {
          submitting = false;
          resume();
        }
      });
      function frame(now) {
        if (!submitting) {
          sample(now);
          if (now - lastSave >= 250) {
            save();
            lastSave = now;
          }
        }
        requestAnimationFrame(frame);
      }
      root.dataset.enhanced = 'true';
      native.classList.add('cf-native-hidden');
      timing.classList.add('cf-native-hidden');
      save();
      if (supported) requestAnimationFrame(frame);

6. Verify the assembled survey

Search your XML for BUILD:. There should be no insertion markers left. Check that there is one outer <survey>, one CSS hook and one JavaScript hook, then save in Decipher and resolve any XML errors before opening the test link. The complete example below is the reference for comparing your assembled document.

Interpret timing states before comparing results

StateDuration cellsInterpretation
0-1Timing has not initialized.
10Instrumented, with zero qualifying time so far.
2NonnegativePositive qualifying time; for full-card state, the 1% meter is positive.
3Nonnegative lower boundsIncomplete measurement, such as a long gap, lost cache or image error.
4-1Required measurement APIs are unavailable.

Missing cells mean that feed has no submitted measurement. A state-3 zero is not a complete observed zero. A Like (3 in the feed radio export) is separate from timing state 3: the fields use different code systems. anyms requires at least 1% of full card area, not one visible pixel.

Save the XML and run a test response through all five feeds. Check zero Likes, multiple Likes, undo, keyboard activation and image gestures. Then check a phone-width layout and perform an actual background-tab test in your browser.

For exposure timing, partially show an ad: at roughly 25% visible, anyms should increase while halfms remains unchanged. Show more than 50%, and both should increase. Scroll it fully offscreen and both should pause. Revisit it and confirm accumulation resumes. On a normal same-tab reload, totals should be retained without doubling.

Inspect the completed export. For feed 2, row 7, join these fields:

  • Feed2r7 for the current Like state.
  • Time2r7anyms, Time2r7halfms and Time2r7exposurestate for full-card exposure.
  • Offer2r7kind to distinguish sponsored (1) from organic (0).
  • Offer2r7item, Offer2r7creative, Offer2r7campaign and Offer2r7context for placement, creative and context.
  • DesignVersion, DesignRevision and ExposureRevision to identify the assignment and measurement definitions.

The supplied XML writes DesignRevision=5 and ExposureRevision=1. Within a submitted, supported measurement, halfms must never exceed anyms. Preserve revision identifiers when analyzing exports; the same placement ID can refer to different content in a different design revision.

The repository records native desktop and mobile-width checks and deterministic timing tests. A real background-tab transition, physical phones and cross-browser behavior remain explicit verification gaps. Check those in the environments your respondents will use.

Reuse the component with Questra Fine Tuning

Put this activity into a Questra Fine Tuning template so Questra can create social-feed elements for you and your team. The importable template export bundles the shared base, SocialFeed component, design file and all 26 JPEGs.

Import it from Fine Tuning, select it when programming, and request tasks "1" through "5" once each, in order, in main. Each component takes a string input such as {"task":"1"} and supplies its own page break. The base owns the shared resources and assignment, so keep one shared base for the five tasks.

For a different campaign, coordinate changes to copy resources, images, design assignments and revisions. Ask Questra to use your team's template, then verify the generated survey and export before fielding. Reusing the component does not remove the need to define the experiment or check what its timing fields mean.

Complete example XML

After uploading the files from step 1, you can paste this entire document into a new test survey instead of assembling the sections individually. Replacing every scaffold marker with its matching block produces this exact XML. Do not append it to the document you have already assembled.

This is the formatted complete source at revision 109fa76. The component-examples repository contains the matching assets, design files where applicable, and Fine Tuning templates.

<survey
  name="Social feed"
  alt="Social feed"
  compat="144"
  fir="on"
  html:showNumber="0"
  builder:wizardCompleted="1"
  state="testing"
  ss:enableNavigation="0"
  extraVariables="source"
>
  <style name="respview.client.css" mode="after"><![CDATA[
    <!-- questra-theme:start -->
    <style>
      /* Questra brand: questra-workspace/brand/motion/motion.js, BRAND (lines 51–52).
         Shared shell and native controls only. No font or stylesheet network dependency. */
      :root {
        --qt-chalk: #f5f1ec;
        --qt-coral: #ff505d;
        --qt-slate: #103743;
        --qt-line: #10374333;
        --qt-surface: #fff;
        --qt-radius: 24px;
        color-scheme: light;
      }
      html {
        background: var(--qt-chalk);
      }
      html body,
      html body.survey-page {
        margin: 0;
        background: var(--qt-chalk);
        color: var(--qt-slate);
        font:
          16px/1.5 Arial,
          Helvetica,
          sans-serif;
        min-height: 100vh;
      }
      body #survey {
        box-sizing: border-box;
        width: 100%;
        max-width: 1240px;
        margin: 0 auto;
        padding: 28px 32px 48px;
        background: transparent;
        border: 0;
        box-shadow: none;
        border-radius: 0;
      }
      body .survey-section,
      body .survey-body {
        box-sizing: border-box;
        max-width: none;
        width: 100%;
        margin: 0;
        padding: 0;
        background: transparent;
        border: 0;
        box-shadow: none;
      }
      body .survey-header,
      body .survey-footer {
        background: transparent;
        color: var(--qt-slate);
      }
      body .question {
        box-sizing: border-box;
        margin: 24px 0;
        padding: 0;
        background: transparent;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        color: var(--qt-slate);
      }
      body .question-text {
        font-size: clamp(22px, 3vw, 34px);
        line-height: 1.2;
        letter-spacing: -0.6px;
        color: var(--qt-slate);
      }
      body .instruction-text {
        color: var(--qt-slate);
        line-height: 1.6;
      }
      body .answers {
        max-width: 100%;
        overflow-x: auto;
      }
      body .answers input:not([type='radio']):not([type='checkbox']):not([type='hidden']),
      body .answers textarea,
      body .answers select {
        box-sizing: border-box;
        max-width: 100%;
        font: inherit;
        color: var(--qt-slate);
        background: white;
        border: 1px solid var(--qt-slate);
        border-radius: 8px;
        padding: 10px;
      }
      body input[type='radio'],
      body input[type='checkbox'] {
        accent-color: var(--qt-slate);
        min-width: 20px;
        min-height: 20px;
      }
      body .survey-buttons {
        display: flex;
        flex-wrap: wrap;
        gap: 12px;
        justify-content: flex-end;
        padding: 24px 0;
      }
      body #btn_continue,
      body #btn_finish,
      body #btn_back {
        font:
          700 16px/1.4 Arial,
          sans-serif;
        min-height: 48px;
        padding: 13px 26px;
        border: 2px solid var(--qt-slate);
        border-radius: 999px;
        background: var(--qt-slate);
        color: var(--qt-chalk);
        cursor: pointer;
        box-shadow: 4px 4px 0 var(--qt-coral);
      }
      body #btn_back {
        background: transparent;
        color: var(--qt-slate);
        box-shadow: none;
      }
      body :focus-visible {
        outline: 3px solid var(--qt-slate);
        outline-offset: 4px;
      }
      body .survey-error,
      body .question-error,
      body .error-text {
        color: var(--qt-slate);
        background: var(--qt-chalk);
        border-left: 4px solid var(--qt-coral);
        padding: 12px;
      }
      body .progress-bar,
      body [role='progressbar'] {
        display: none !important;
      }
      .qt-footer {
        display: flex;
        justify-content: center;
        padding: 32px 20px 40px;
        background: transparent;
      }
      .qt-footer img {
        display: block;
        width: 120px;
        height: 36px;
        object-fit: contain;
      }
      /* The optional early gate never hides the form, navigation or validation messages.
         CSS provides an independent fail-open deadline even if a later script throws. */
      html.qt-pending .question,
      html.qt-pending .outfit-ui,
      html.qt-pending .sh-ui {
        visibility: hidden;
        animation: qt-reveal 0s 1.8s forwards;
      }
      html.qt-pending .survey-body:before {
        content: 'Preparing your activity…';
        display: block;
        padding: 24px;
        border-left: 4px solid var(--qt-coral);
        animation: qt-dismiss 0s 1.8s forwards;
      }
      \@keyframes qt-reveal {
        to {
          visibility: visible;
        }
      }
      \@keyframes qt-dismiss {
        to {
          display: none;
          visibility: hidden;
          height: 0;
          padding: 0;
        }
      }
      \@media (max-width: 650px) {
        body #survey {
          padding: 16px 12px 32px;
        }
        body .question {
          padding: 0;
          border-radius: 0;
          margin: 16px 0;
        }
      }
      \@media (prefers-reduced-motion: reduce) {
        body {
          scroll-behavior: auto;
        }
      }
    </style>
 
    <script>
      /* Runs inline in the head, before body parsing; no jQuery dependency. */
      (function () {
        'use strict';
        var root = document.documentElement;
        var expired = false;
        root.classList.add('qt-pending');
        function reveal(fallback) {
          if (fallback) expired = true;
          root.classList.remove('qt-pending');
        }
        window.QuestraTheme = {
          canEnhance: function () {
            return !expired;
          },
          ready: function () {
            reveal(false);
          }
        };
        setTimeout(function () {
          reveal(true);
        }, 1800);
        // Keyboard/pointer intent takes precedence over cosmetic loading.
        document.addEventListener(
          'keydown',
          function () {
            reveal(true);
          },
          { once: true, capture: true }
        );
        document.addEventListener(
          'pointerdown',
          function () {
            reveal(true);
          },
          { once: true, capture: true }
        );
        window.addEventListener('pageshow', function (event) {
          if (event.persisted) reveal(true);
        });
      })();
    </script>
    <!-- questra-theme:end -->
    <style>
      /* All presentation stays within this question or its initialization placeholder. */
      .question.cf-feed {
        color: #050505;
        font-family: Arial, Helvetica, sans-serif;
        -webkit-font-smoothing: antialiased;
      }
      .question.cf-feed .question-text,
      .question.cf-feed .instruction-text {
        max-width: 590px;
        margin-left: auto;
        margin-right: auto;
        box-sizing: border-box;
      }
      .question.cf-feed .question-text {
        font:
          600 17px/1.3 Arial,
          Helvetica,
          sans-serif;
        margin-bottom: 6px;
      }
      .question.cf-feed .instruction-text {
        font:
          14px/1.45 Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin-top: 0;
        margin-bottom: 16px;
      }
      .question.cf-feed .cf-round {
        display: block;
        font:
          12px/16px Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin-bottom: 8px;
      }
      .question.cf-timing.cf-native-hidden {
        display: none !important;
      }
      .question.cf-feed .cf-native-hidden {
        display: none !important;
      }
      .question.cf-feed .cf-art {
        aspect-ratio: 4/3;
      }
      .question.cf-feed .cf-art img:not([src]) {
        visibility: hidden;
      }
      .question.cf-feed .cf-art[data-failed]::after {
        content: 'Image unavailable';
        position: absolute;
        inset: 45% 0 auto;
        text-align: center;
        font:
          14px Arial,
          sans-serif;
        color: #65676b;
      }
      .question.cf-feed .cf-art[data-loading]::after {
        content: 'Loading image…';
        position: absolute;
        inset: 45% 0 auto;
        text-align: center;
        font:
          14px Arial,
          sans-serif;
        color: #65676b;
      }
      /* A still placeholder reserves the same local column before enhancement. */
      .cf-init .cf-skeleton {
        content: '';
        display: block;
        box-sizing: border-box;
        max-width: 590px;
        height: 560px;
        margin: 0 auto;
        border: 1px solid #e4e6eb;
        border-radius: 8px;
        background:
          linear-gradient(#e4e6eb, #e4e6eb) 16px 18px/40px 40px no-repeat,
          linear-gradient(#e4e6eb, #e4e6eb) 68px 23px/140px 12px no-repeat,
          linear-gradient(#eef0f2, #eef0f2) 68px 43px/86px 9px no-repeat,
          linear-gradient(#e4e6eb, #e4e6eb) 16px 82px/78% 12px no-repeat,
          linear-gradient(#eef0f2, #eef0f2) 16px 104px/56% 12px no-repeat,
          linear-gradient(#e4e6eb, #e4e6eb) 0 140px/100% 380px no-repeat,
          #fff;
      }
      .cf-init {
        max-width: 590px;
        margin: 0 auto;
        font-family: Arial, Helvetica, sans-serif;
        color: #050505;
      }
      .cf-init .cf-round {
        font:
          12px/16px Arial,
          sans-serif;
        color: #65676b;
        margin-bottom: 8px;
      }
      .cf-init h2 {
        font:
          600 17px/1.3 Arial,
          sans-serif;
        margin: 0 0 6px;
      }
      .cf-init p {
        font:
          14px/1.45 Arial,
          sans-serif;
        color: #65676b;
        margin: 0 0 16px;
      }
      .question.cf-feed .cf-layout {
        max-width: 590px;
        margin: 0 auto;
        padding: 0;
        box-sizing: border-box;
        background: #f0f2f5;
      }
      .question.cf-feed .cf-instructions {
        margin-bottom: 16px;
        padding: 16px;
        background: white;
        border-radius: 8px;
        box-shadow: 0 1px 2px #00000020;
      }
      .question.cf-feed .cf-round {
        font-size: 12px;
        line-height: 16px;
        color: #65676b;
        margin-bottom: 8px;
      }
      .question.cf-feed .cf-instructions h2 {
        font:
          600 17px/1.3 Arial,
          Helvetica,
          sans-serif;
        margin: 0 0 6px;
        color: #050505;
      }
      .question.cf-feed .cf-instructions p {
        font:
          14px/1.45 Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin: 0;
      }
      .question.cf-feed .cf-card {
        background: #fff;
        border: 0;
        border-radius: 8px;
        overflow: hidden;
        margin: 0 0 16px;
        box-shadow: 0 1px 2px #00000026;
      }
      .question.cf-feed .cf-author-row {
        display: flex;
        align-items: center;
        gap: 9px;
        padding: 12px 16px 0;
      }
      .question.cf-feed .cf-avatar {
        display: block;
        flex: 0 0 40px;
        width: 40px;
        height: 40px;
        border-radius: 50%;
        object-fit: cover;
        box-shadow: inset 0 0 0 1px #0000000d;
      }
      .question.cf-feed .cf-brand-avatar {
        display: flex;
        align-items: center;
        justify-content: center;
        font:
          700 14px/1 Arial,
          Helvetica,
          sans-serif;
        letter-spacing: -0.5px;
      }
      .question.cf-feed .cf-brand-1 {
        background: #dfe9e1;
        color: #2b5039;
      }
      .question.cf-feed .cf-brand-2 {
        background: #eddfcc;
        color: #583b24;
      }
      .question.cf-feed .cf-brand-3 {
        background: #e5eadc;
        color: #50633d;
      }
      .question.cf-feed .cf-author-details {
        min-width: 0;
      }
      .question.cf-feed .cf-source {
        font:
          600 15px/20px Arial,
          Helvetica,
          sans-serif;
        color: #050505;
      }
      .question.cf-feed .cf-post-meta {
        display: flex;
        align-items: center;
        gap: 3px;
        font:
          12px/16px Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin-top: 1px;
      }
      .question.cf-feed .cf-post-meta svg {
        width: 12px;
        height: 12px;
      }
      .question.cf-feed .cf-copy {
        font:
          15px/1.42 Arial,
          Helvetica,
          sans-serif;
        padding: 12px 16px 14px;
        margin: 0 !important;
        color: #050505;
        white-space: pre-line;
        overflow-wrap: break-word;
      }
      .question.cf-feed .cf-art {
        position: relative;
        background: #e4e6eb;
        touch-action: pan-y;
        user-select: none;
        cursor: default;
      }
      .question.cf-feed .cf-art > img {
        display: block;
        width: 100%;
        height: auto;
        aspect-ratio: 4/3;
        object-fit: cover;
      }
      .question.cf-feed .cf-offer {
        background: #f0f2f5;
        border-bottom: 1px solid #dadde1;
        padding: 12px 16px;
      }
      .question.cf-feed .cf-domain {
        font:
          11px/16px Arial,
          Helvetica,
          sans-serif;
        text-transform: uppercase;
        letter-spacing: 0.25px;
        color: #65676b;
      }
      .question.cf-feed .cf-offer-title {
        font:
          600 16px/21px Arial,
          Helvetica,
          sans-serif;
        color: #050505;
        margin-top: 3px;
      }
      .question.cf-feed .cf-offer-detail {
        font:
          13px/18px Arial,
          Helvetica,
          sans-serif;
        color: #65676b;
        margin-top: 3px;
      }
      .question.cf-feed .cf-actions {
        margin: 0 16px;
        padding: 4px 0;
        display: flex;
        border-top: 1px solid #e4e6eb;
      }
      .question.cf-feed .cf-like {
        display: flex !important;
        align-items: center;
        justify-content: center;
        gap: 7px;
        width: 100%;
        border: 0 !important;
        background: transparent !important;
        color: #65676b !important;
        border-radius: 4px !important;
        padding: 9px 14px !important;
        font:
          600 14px/20px Arial,
          Helvetica,
          sans-serif !important;
        cursor: pointer;
        min-height: 40px;
        box-shadow: none !important;
        transition: background 0.12s;
      }
      .question.cf-feed .cf-like svg {
        width: 19px;
        height: 19px;
        flex: 0 0 19px;
      }
      .question.cf-feed .cf-like:hover {
        background: #f2f2f2 !important;
      }
      .question.cf-feed .cf-like[aria-pressed='true'] {
        color: #0866ff !important;
      }
      .question.cf-feed .cf-like[aria-pressed='true'] svg path {
        fill: #e7f0ff;
      }
      .question.cf-feed .cf-like:active {
        background: #e4e6eb !important;
      }
      .question.cf-feed .cf-like:focus-visible {
        outline: 3px solid #0866ff;
        outline-offset: 2px;
      }
      .question.cf-feed .cf-like-flash {
        position: absolute;
        left: 50%;
        top: 50%;
        width: 72px;
        height: 72px;
        margin: -36px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 50%;
        background: #0866ff;
        color: #fff;
        box-shadow: 0 3px 12px #0004;
        opacity: 0;
        pointer-events: none;
      }
      .question.cf-feed .cf-like-flash svg {
        width: 38px;
        height: 38px;
      }
      .question.cf-feed .cf-liked-flash .cf-like-flash {
        animation: cf-pop 0.65s ease-out both;
      }
      \@keyframes cf-pop {
        0% {
          opacity: 0;
          transform: scale(0.6);
        }
        20%,
        65% {
          opacity: 0.95;
          transform: scale(1);
        }
        100% {
          opacity: 0;
          transform: scale(1.08);
        }
      }
      \@media (max-width: 600px) {
        .question.cf-feed .cf-card {
          margin-bottom: 10px;
        }
        .question.cf-feed .cf-author-row,
        .question.cf-feed .cf-copy {
          padding-left: 12px;
          padding-right: 12px;
        }
        .question.cf-feed .cf-actions {
          margin: 0 12px;
        }
        .question.cf-feed .cf-offer {
          padding: 11px 12px;
        }
      }
      \@media (prefers-reduced-motion: reduce) {
        .question.cf-feed .cf-like {
          transition: none;
        }
        .question.cf-feed .cf-liked-flash .cf-like-flash {
          animation: none;
        }
      }
 
      .question.cf-feed .cf-round,
      .cf-init .cf-round {
        display: none;
      }
    </style>
  ]]></style>
  <style name="respview.client.js" mode="after" wrap="ready"><![CDATA[
    /* Shared by the native component and deterministic timing tests. */
    (function (scope) {
      'use strict';
      function fraction(rect, width, height) {
        const area = Math.min(rect.width, width) * Math.min(rect.height, height);
        if (!(area > 0)) return 0;
        const w = Math.max(0, Math.min(rect.right, width) - Math.max(rect.left, 0));
        const h = Math.max(0, Math.min(rect.bottom, height) - Math.max(rect.top, 0));
        return Math.min(1, (w * h) / area);
      }
      function meter(total = 0, partial = false) {
        return {
          total: Math.max(0, total),
          partial,
          last: null,
          eligible: false,
          sample(now, eligible) {
            if (this.last !== null) {
              const dt = now - this.last;
              if (this.eligible && eligible && dt >= 0 && dt <= 250) this.total += dt;
              else if (this.eligible && eligible && dt > 250) this.partial = true;
            }
            this.last = now;
            this.eligible = eligible;
            return Math.floor(this.total);
          },
          pause() {
            this.last = null;
            this.eligible = false;
          },
          state() {
            return this.partial ? 3 : this.total >= 1 ? 2 : 1;
          }
        };
      }
      // Full card denominator; clip rectangles represent viewport and overflow ancestors.
      function fullFraction(rect, clips) {
        if (!(rect.width > 0 && rect.height > 0)) return 0;
        let left = rect.left,
          right = rect.right,
          top = rect.top,
          bottom = rect.bottom;
        for (const clip of clips) {
          left = Math.max(left, clip.left);
          right = Math.min(right, clip.right);
          top = Math.max(top, clip.top);
          bottom = Math.min(bottom, clip.bottom);
        }
        return (
          (Math.max(0, right - left) * Math.max(0, bottom - top)) / (rect.width * rect.height)
        );
      }
      const api = { fraction, fullFraction, meter };
      if (typeof module !== 'undefined' && module.exports) module.exports = api;
      else scope.SocialFeedTiming = api;
    })(typeof window === 'undefined' ? globalThis : window);
 
    (function () {
      'use strict';
      if (window.QuestraTheme && !window.QuestraTheme.canEnhance()) return;
      if (document.querySelector('#comment_Initialize')) {
        const start = document.querySelector('#btn_continue');
        if (start && !start.disabled) start.click();
        return;
      }
      const root = document.querySelector('.question.cf-feed');
      if (!root || root.dataset.enhanced) return;
      const native = root.querySelector('.answers'),
        form = root.closest('form'),
        next = form && form.querySelector('#btn_continue');
      const config = document.querySelector('.cf-config'),
        timing = document.querySelector('.question.cf-timing');
      if (!native || !next || !config || !timing) return;
      const groups = new Map();
      native.querySelectorAll('input[type=radio]').forEach(i => {
        if (!groups.has(i.name)) groups.set(i.name, []);
        groups.get(i.name).push(i);
      });
      function column(input, code) {
        return (input.closest('td')?.getAttribute('headers') || '')
          .split(/\s+/)
          .some(h => h.endsWith('_' + code));
      }
      const timeRows = Array.from(timing.querySelectorAll('tr')).filter(tr =>
        tr.querySelector('input[type=text],input[type=number]')
      );
      const rows = Array.from(groups.values()).map((inputs, index) => {
        const tr = inputs[0].closest('tr'),
          legend = tr && tr.querySelector('.row-legend'),
          codes = {};
        inputs.forEach(input =>
          ['c1', 'c2', 'c3'].forEach(code => {
            if (column(input, code)) codes[code] = input;
          })
        );
        const timeInputs = Array.from(timeRows[index]?.querySelectorAll('input') || []);
        return {
          inputs,
          legend,
          codes,
          ms: timeInputs.find(i => column(i, 'ms')),
          state: timeInputs.find(i => column(i, 'state')),
          anyms: timeInputs.find(i => column(i, 'anyms')),
          halfms: timeInputs.find(i => column(i, 'halfms')),
          exposurestate: timeInputs.find(i => column(i, 'exposurestate')),
          card: null,
          touch: null,
          lastGesture: -Infinity,
          lastButton: -Infinity
        };
      });
      if (
        !rows.length ||
        rows.some(
          r =>
            !r.legend ||
            Object.keys(r.codes).length !== 3 ||
            !r.ms ||
            !r.state ||
            !r.anyms ||
            !r.halfms ||
            !r.exposurestate
        )
      )
        return;
 
      const feed = Number(config.dataset.feed),
        count = Number(config.dataset.feeds),
        version = config.dataset.version;
      const storageKey =
        'adfeed-exposure-v1:' +
        location.pathname +
        ':' +
        config.dataset.session +
        ':' +
        feed +
        ':' +
        version;
      const clock = window.SocialFeedTiming,
        supported = !!(
          clock &&
          window.performance &&
          typeof performance.now === 'function' &&
          typeof document.hasFocus === 'function' &&
          'visibilityState' in document &&
          typeof IntersectionObserver === 'function'
        );
      let restored = null,
        storageOK = true;
      try {
        const value = JSON.parse(sessionStorage.getItem(storageKey) || 'null');
        if (value && value.schema === 6 && value.items.length === rows.length)
          restored = value.items;
      } catch (e) {
        storageOK = false;
      }
      const navigation = window.performance?.getEntriesByType?.('navigation')[0]?.type;
      const gestureNow = () => (window.performance?.now ? performance.now() : Date.now());
      const lostCache =
        !restored && (navigation === 'reload' || navigation === 'back_forward');
      let submitting = false,
        paused = false,
        lastSave = 0;
      function selected(r) {
        return ['c1', 'c2', 'c3'].find(c => r.codes[c].checked) || 'c1';
      }
      function choose(r, c) {
        if (!r.codes[c].checked) r.codes[c].click();
        render(r);
        save();
      }
      function sync() {
        ui.dataset.pageVisible = document.visibilityState;
        ui.dataset.pageFocused = String(
          typeof document.hasFocus === 'function' && document.hasFocus()
        );
        rows.forEach(r => {
          r.ms.value = supported ? String(Math.floor(r.meter.total)) : '-1';
          r.state.value = supported ? String(r.meter.state()) : '4';
          r.anyms.value = supported ? String(Math.floor(r.anyMeter.total)) : '-1';
          r.halfms.value = supported ? String(Math.floor(r.halfMeter.total)) : '-1';
          r.exposurestate.value = supported
            ? String(
                r.anyMeter.partial || r.halfMeter.partial ? 3 : r.anyMeter.total >= 1 ? 2 : 1
              )
            : '4';
        });
      }
      function save() {
        sync();
        try {
          sessionStorage.setItem(
            storageKey,
            JSON.stringify({
              schema: 6,
              items: rows.map(r => ({
                like: selected(r),
                ms: r.meter.total,
                partial: r.meter.partial,
                anyms: r.anyMeter.total,
                halfms: r.halfMeter.total,
                exposurepartial: r.anyMeter.partial || r.halfMeter.partial
              }))
            })
          );
        } catch (e) {
          storageOK = false;
          rows.forEach(r => {
            r.meter.partial = true;
            r.anyMeter.partial = true;
            r.halfMeter.partial = true;
          });
          sync();
        }
      }
      const thumb =
        '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M7.5 10.5v10H4a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h3.5Zm0 0L12 3c.4-.7 1.4-.7 1.8 0 .7 1.3.5 3.2-.1 5H19a2 2 0 0 1 2 2.4l-1.5 8.5a2 2 0 0 1-2 1.6h-10" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/></svg>';
      function render(r) {
        if (!r.card) return;
        const yes = selected(r) === 'c3',
          b = r.card.querySelector('.cf-like');
        b.setAttribute('aria-pressed', String(yes));
        b.innerHTML = thumb + '<span>' + (yes ? 'Liked' : 'Like') + '</span>';
      }
      const ui = document.createElement('section');
      ui.className = 'cf-layout';
      ui.innerHTML = '<div class="cf-stream"></div>';
      root.appendChild(ui);
      const stream = ui.querySelector('.cf-stream');
      rows.forEach((r, i) => {
        const cached = restored?.[i],
          nativeMs = Number(r.ms.value);
        const total =
          cached && Number.isFinite(cached.ms) && cached.ms >= 0
            ? cached.ms
            : Math.max(0, nativeMs || 0);
        r.meter = clock.meter(
          total,
          !!cached?.partial || !storageOK || lostCache || Number(r.state.value) === 3
        );
        const restoredTotal = key =>
          Math.max(0, Number(r[key].value) || 0, Number(cached?.[key]) || 0);
        const partial =
          !!cached?.exposurepartial ||
          !storageOK ||
          lostCache ||
          Number(r.exposurestate.value) === 3;
        r.anyMeter = clock.meter(restoredTotal('anyms'), partial);
        r.halfMeter = clock.meter(restoredTotal('halfms'), partial);
        const card = document.createElement('article');
        r.card = card;
        card.className = 'cf-card';
        card.dataset.item = String(i + 1);
        card.innerHTML =
          r.legend.innerHTML +
          '<div class="cf-actions"><button type="button" class="cf-like" aria-label="Like post ' +
          (i + 1) +
          '" aria-pressed="false">♡ Like</button></div>';
        stream.appendChild(card);
        card.querySelectorAll('img[data-src]').forEach(photo => {
          photo.loading = i < 2 ? 'eager' : 'lazy';
          photo.decoding = 'async';
          if (i === 0) photo.fetchPriority = 'high';
          photo.src = photo.dataset.src;
        });
        if (cached && ['c1', 'c2', 'c3'].includes(cached.like)) r.codes[cached.like].click();
        else if (!r.inputs.some(x => x.checked)) r.codes.c1.click();
        function toggle() {
          if (submitting) return;
          choose(r, selected(r) === 'c3' ? (r.meter.total >= 1 ? 'c2' : 'c1') : 'c3');
        }
        // A button click toggles immediately; subsequent click events in the same multi-click gesture do not.
        card.querySelector('.cf-like').addEventListener('click', e => {
          const now = gestureNow();
          if (e.detail > 1 && now - r.lastButton < 420) return;
          r.lastButton = now;
          toggle();
        });
        function imageGesture() {
          const now = gestureNow();
          if (now - r.lastGesture < 420) return;
          r.lastGesture = now;
          toggle();
          if (selected(r) === 'c3') {
            art.classList.remove('cf-liked-flash');
            void art.offsetWidth;
            art.classList.add('cf-liked-flash');
          }
        }
        const art = card.querySelector('.cf-art');
        if (art) {
          const flash = document.createElement('span');
          flash.className = 'cf-like-flash';
          flash.setAttribute('aria-hidden', 'true');
          flash.innerHTML = thumb;
          art.appendChild(flash);
          const photo = art.querySelector('img');
          art.dataset.loading = 'true';
          const loaded = () => {
            delete art.dataset.loading;
            r.rendered = !!(photo.complete && photo.naturalWidth > 0);
          };
          photo?.addEventListener('load', loaded);
          if (photo?.complete && photo.naturalWidth > 0) loaded();
          photo?.addEventListener('error', () => {
            delete art.dataset.loading;
            art.dataset.failed = 'true';
            r.rendered = false;
            r.meter.partial = true;
            r.anyMeter.partial = true;
            r.halfMeter.partial = true;
            save();
          });
          art.addEventListener('dblclick', e => {
            e.preventDefault();
            imageGesture();
          });
          art.addEventListener('pointerup', e => {
            if (e.pointerType !== 'touch') return;
            const now = gestureNow(),
              t = r.touch;
            if (
              t &&
              now - t.time < 340 &&
              Math.hypot(e.clientX - t.x, e.clientY - t.y) < 25
            ) {
              imageGesture();
              r.touch = null;
            } else r.touch = { time: now, x: e.clientX, y: e.clientY };
          });
          art.addEventListener('pointercancel', () => (r.touch = null));
        }
        render(r);
      });
      const observed = new Map(rows.map(r => [r.card, r]));
      const observer = supported
        ? new IntersectionObserver(
            entries => {
              entries.forEach(entry => {
                const r = observed.get(entry.target);
                if (r) r.intersects = entry.isIntersecting;
              });
            },
            { threshold: 0 }
          )
        : null;
      if (observer) rows.forEach(r => observer.observe(r.card));
      function fullVisibleFraction(card) {
        const vv = window.visualViewport;
        const clips = [
          {
            left: vv ? vv.offsetLeft : 0,
            top: vv ? vv.offsetTop : 0,
            right: vv ? vv.offsetLeft + vv.width : innerWidth,
            bottom: vv ? vv.offsetTop + vv.height : innerHeight
          }
        ];
        for (let el = card.parentElement; el; el = el.parentElement) {
          const style = getComputedStyle(el),
            rect = el.getBoundingClientRect();
          const x = /(auto|scroll|hidden|clip)/.test(style.overflowX),
            y = /(auto|scroll|hidden|clip)/.test(style.overflowY);
          if (x || y)
            clips.push({
              left: x ? rect.left + el.clientLeft : -Infinity,
              right: x ? rect.left + el.clientLeft + el.clientWidth : Infinity,
              top: y ? rect.top + el.clientTop : -Infinity,
              bottom: y ? rect.top + el.clientTop + el.clientHeight : Infinity
            });
        }
        return clock.fullFraction(card.getBoundingClientRect(), clips);
      }
      function active() {
        return (
          supported &&
          !submitting &&
          !paused &&
          document.visibilityState === 'visible' &&
          document.hasFocus()
        );
      }
      function sample(now) {
        const enabled = active();
        rows.forEach(r => {
          const photo = r.card.querySelector('.cf-art img');
          const ready = photo && photo.complete && photo.naturalWidth > 0;
          const eligible =
            enabled &&
            root.dataset.enhanced === 'true' &&
            r.rendered &&
            ready &&
            r.intersects === true &&
            clock.fraction(r.card.getBoundingClientRect(), innerWidth, innerHeight) >= 0.5;
          r.meter.sample(now, eligible);
          const fraction =
            enabled && root.dataset.enhanced === 'true' && r.rendered && ready
              ? fullVisibleFraction(r.card)
              : 0;
          r.anyMeter.sample(now, fraction >= 0.01);
          r.halfMeter.sample(now, fraction >= 0.5);
          if (r.meter.total >= 1 && selected(r) === 'c1') {
            r.codes.c2.click();
            render(r);
          }
        });
      }
      function flush() {
        if (supported) sample(performance.now());
        save();
      }
      function pause() {
        flush();
        paused = true;
        rows.forEach(r => {
          r.meter.pause();
          r.anyMeter.pause();
          r.halfMeter.pause();
        });
      }
      function resume() {
        paused = false;
        rows.forEach(r => {
          r.meter.pause();
          r.anyMeter.pause();
          r.halfMeter.pause();
        });
        if (supported) sample(performance.now());
      }
      // Keep native navigation and validation intact. Save before native handlers read fields.
      next.addEventListener('click', flush, true);
      form.addEventListener('submit', flush, true);
      window.addEventListener('blur', pause);
      window.addEventListener('focus', resume);
      document.addEventListener('visibilitychange', () => {
        if (document.visibilityState === 'hidden') pause();
        else resume();
      });
      window.addEventListener('pagehide', () => {
        pause();
        submitting = true;
      });
      window.addEventListener('beforeunload', flush);
      window.addEventListener('pageshow', e => {
        if (e.persisted) {
          submitting = false;
          resume();
        }
      });
      function frame(now) {
        if (!submitting) {
          sample(now);
          if (now - lastSave >= 250) {
            save();
            lastSave = now;
          }
        }
        requestAnimationFrame(frame);
      }
      root.dataset.enhanced = 'true';
      native.classList.add('cf-native-hidden');
      timing.classList.add('cf-native-hidden');
      save();
      if (supported) requestAnimationFrame(frame);
    })();
 
    if (window.QuestraTheme) window.QuestraTheme.ready();
  ]]></style>
  <exec when="init"><![CDATA[
def loadSocialDesign(fname):
    f = open("%s/%s" % (gv.survey.path, fname))
    records = [line.strip("\r\n").split("\t") for line in f.readlines()]
    f.close()
    design = {}
    for row in records[1:]:
        design[(int(row[0]), int(row[1]), int(row[2]))] = [int(n) for n in row[3:]]
    return design
socialDesign = loadSocialDesign("social-design.dat")
]]></exec>
  <res label="copy1">Sunday bread experiment, attempt number four. Finally got the crust right. Half of this disappeared before it had even cooled down 😂</res>
  <res label="byline1"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-09.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Maya Bennett</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer1"><![CDATA[]]></res>
  <res label="copy2">We said we were going for a quick walk. Three hours and one very steep hill later… absolutely worth it.</res>
  <res label="byline2"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-02.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Ben Carter</div><div class="cf-post-meta"><span>38 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer2"><![CDATA[]]></res>
  <res label="copy3">Took the long way home and found this little street. Making a mental note to come back when the roses are out.</res>
  <res label="byline3"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-03.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Elena Morris</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer3"><![CDATA[]]></res>
  <res label="copy4">A few days by the sea was exactly what we needed. This was the view on the morning coffee walk.</res>
  <res label="byline4"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-04.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Sam Rivera</div><div class="cf-post-meta"><span>3 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer4"><![CDATA[]]></res>
  <res label="copy5">Three weeks ago these were tiny cuttings in a jam jar. Now I apparently have a windowsill herb garden 🌱</res>
  <res label="byline5"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-05.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Priya Shah</div><div class="cf-post-meta"><span>54 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer5"><![CDATA[]]></res>
  <res label="copy6">Rain canceled our plans, so I’m calling this an excellent alternative. Tea, a blanket and the book I keep meaning to finish.</res>
  <res label="byline6"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-06.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Jordan Ellis</div><div class="cf-post-meta"><span>25 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer6"><![CDATA[]]></res>
  <res label="copy7">First watercolor class done. The sky was supposed to be blue, but I’m choosing to call it creative freedom.</res>
  <res label="byline7"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-07.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Theo Park</div><div class="cf-post-meta"><span>4 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer7"><![CDATA[]]></res>
  <res label="copy8">Our extremely ambitious weekend plan: bring lunch to the park and stay until the coffee runs out.</res>
  <res label="byline8"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-08.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Amara Brooks</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer8"><![CDATA[]]></res>
  <res label="copy9">The kitchen smells incredible. Trying very hard to save some of this loaf for breakfast tomorrow.</res>
  <res label="byline9"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-09.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Nora Patel</div><div class="cf-post-meta"><span>47 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer9"><![CDATA[]]></res>
  <res label="copy10">Found a quieter route along the river. A little longer, a lot nicer. This might become the regular Sunday ride.</res>
  <res label="byline10"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-10.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Luca Reed</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer10"><![CDATA[]]></res>
  <res label="copy11">No alarm, no rush, and the good mug. Keeping Saturday morning exactly like this for as long as possible.</res>
  <res label="byline11"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-01.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Maya Bennett</div><div class="cf-post-meta"><span>31 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer11"><![CDATA[]]></res>
  <res label="copy12">The weather forecast said cloudy. I’m very happy it was wrong. Even remembered to pack enough snacks this time.</res>
  <res label="byline12"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-02.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Ben Carter</div><div class="cf-post-meta"><span>5 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer12"><![CDATA[]]></res>
  <res label="copy13">The neighborhood is looking especially good this week. Whoever planted all these flowers deserves a thank-you.</res>
  <res label="byline13"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-03.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Elena Morris</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer13"><![CDATA[]]></res>
  <res label="copy14">Went down to the harbor before everyone else woke up. Just the boats, the gulls and a very peaceful half hour.</res>
  <res label="byline14"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-04.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Sam Rivera</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer14"><![CDATA[]]></res>
  <res label="copy15">The basil has officially survived longer than any of my previous attempts. The secret seems to be not watering it every time I walk past.</res>
  <res label="byline15"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-05.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Priya Shah</div><div class="cf-post-meta"><span>3 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer15"><![CDATA[]]></res>
  <res label="copy16">Picked up a few books at the weekend swap. Came home with more than I brought, which probably defeats the point.</res>
  <res label="byline16"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-06.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Jordan Ellis</div><div class="cf-post-meta"><span>49 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer16"><![CDATA[]]></res>
  <res label="copy17">Cleared a corner of the table and got the paints out again. It’s been months. Forgot how quickly an afternoon disappears doing this.</res>
  <res label="byline17"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-07.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Theo Park</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer17"><![CDATA[]]></res>
  <res label="copy18">Everyone brought “just a little something” for lunch. We could have fed the entire park.</res>
  <res label="byline18"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-08.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Amara Brooks</div><div class="cf-post-meta"><span>3 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer18"><![CDATA[]]></res>
  <res label="copy19">Made a loaf for a neighbor and then had to make another one because the house smelled too good to give it all away.</res>
  <res label="byline19"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-09.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Nora Patel</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer19"><![CDATA[]]></res>
  <res label="copy20">First ride after finally fixing that squeaky brake. Amazing how much more peaceful cycling is without a soundtrack.</res>
  <res label="byline20"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-10.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Luca Reed</div><div class="cf-post-meta"><span>42 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer20"><![CDATA[]]></res>
  <res label="copy21">A small victory: got up early enough to read a chapter before the day started. Might even try it again tomorrow.</res>
  <res label="byline21"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-01.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Maya Bennett</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer21"><![CDATA[]]></res>
  <res label="copy22">Still finding sand in my shoes from this walk. No complaints. Already planning the next one.</res>
  <res label="byline22"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-02.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Ben Carter</div><div class="cf-post-meta"><span>6 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer22"><![CDATA[]]></res>
  <res label="copy23">Walked to the local bakery instead of driving. Took twice as long because I stopped to look at every garden along the way.</res>
  <res label="byline23"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-03.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Elena Morris</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer23"><![CDATA[]]></res>
  <res label="copy24">One last photo from our little coastal break. The kind of place where you immediately start talking about coming back.</res>
  <res label="byline24"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-04.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Sam Rivera</div><div class="cf-post-meta"><span>4 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer24"><![CDATA[]]></res>
  <res label="copy25">Fresh mint for tea, basil for dinner. Feeling ridiculously proud of these little pots.</res>
  <res label="byline25"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-05.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Priya Shah</div><div class="cf-post-meta"><span>35 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer25"><![CDATA[]]></res>
  <res label="copy26">Put my phone in the other room and actually read for an hour. Leaving this here as a reminder to do that more often.</res>
  <res label="byline26"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-06.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Jordan Ellis</div><div class="cf-post-meta"><span>3 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer26"><![CDATA[]]></res>
  <res label="copy27">The table is a mess and there’s paint on my sleeve, but I’m pretty pleased with how this one is coming along.</res>
  <res label="byline27"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-07.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Theo Park</div><div class="cf-post-meta"><span>58 min</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer27"><![CDATA[]]></res>
  <res label="copy28">Last-minute picnic before the weather turns. Bread, cheese, pears. Sometimes the simple plan is the best one.</res>
  <res label="byline28"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-08.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Amara Brooks</div><div class="cf-post-meta"><span>2 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer28"><![CDATA[]]></res>
  <res label="copy29">Tried the overnight dough recipe everyone keeps recommending. Very little effort, very good toast. This one’s staying in the rotation.</res>
  <res label="byline29"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-09.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Nora Patel</div><div class="cf-post-meta"><span>5 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer29"><![CDATA[]]></res>
  <res label="copy30">Stopped here for five minutes and somehow stayed for twenty. Hard to hurry when the river looks like this.</res>
  <res label="byline30"><![CDATA[<div class="cf-author-row"><img class="cf-avatar" data-src="[rel avatar-10.jpg]" width="40" height="40" alt=""/><div class="cf-author-details"><div class="cf-source">Luca Reed</div><div class="cf-post-meta"><span>1 h</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer30"><![CDATA[]]></res>
  <res label="copy31">Your laptop, water bottle, lunch—and room for the weekend. Meet our 18L Everyday Pack. $59, with free shipping this week.</res>
  <res label="byline31"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-1" aria-hidden="true">AT</span><div class="cf-author-details"><div class="cf-source">Aster Trail</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer31"><![CDATA[<div class="cf-offer"><div class="cf-domain">astertrail.example</div><div class="cf-offer-title">One pack. Every kind of day.</div><div class="cf-offer-detail">$59 · Free shipping</div></div>]]></res>
  <res label="copy32">Workday essentials. Weekend plans. Our Everyday Pack keeps both organized, with a padded laptop sleeve and easy-access bottle pockets. Now $59.</res>
  <res label="byline32"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-1" aria-hidden="true">AT</span><div class="cf-author-details"><div class="cf-source">Aster Trail</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer32"><![CDATA[<div class="cf-offer"><div class="cf-domain">astertrail.example</div><div class="cf-offer-title">The 18L Everyday Pack</div><div class="cf-offer-detail">$59 · 3 colors</div></div>]]></res>
  <res label="copy33">Take the scenic route. A comfortable everyday pack for the commute, the trail and the coffee stop in between. Get 15% off your first order with FIRST15.</res>
  <res label="byline33"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-1" aria-hidden="true">AT</span><div class="cf-author-details"><div class="cf-source">Aster Trail</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer33"><![CDATA[<div class="cf-offer"><div class="cf-domain">astertrail.example</div><div class="cf-offer-title">Pack light. Go a little further.</div><div class="cf-offer-detail">15% off your first order</div></div>]]></res>
  <res label="copy34">A place for everything you actually carry. Discover the 18L Everyday Pack in forest, slate and sand. Free delivery on orders over $50.</res>
  <res label="byline34"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-1" aria-hidden="true">AT</span><div class="cf-author-details"><div class="cf-source">Aster Trail</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer34"><![CDATA[<div class="cf-offer"><div class="cf-domain">astertrail.example</div><div class="cf-offer-title">Made for your everyday</div><div class="cf-offer-detail">From $59 · Free delivery over $50</div></div>]]></res>
  <res label="copy35">Good mornings start here. Our smooth House Blend brings notes of chocolate and toasted nuts to your favorite mug. Try a 250g bag for $14.</res>
  <res label="byline35"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-2" aria-hidden="true">K&amp;K</span><div class="cf-author-details"><div class="cf-source">Kettle &amp; Kind</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer35"><![CDATA[<div class="cf-offer"><div class="cf-domain">kettleandkind.example</div><div class="cf-offer-title">Meet your new morning coffee</div><div class="cf-offer-detail">House Blend · $14 / 250g</div></div>]]></res>
  <res label="copy36">Find your favorite cup. Try two of our most-loved blends in the Morning Duo, now $24. Whole bean or ground—your call.</res>
  <res label="byline36"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-2" aria-hidden="true">K&amp;K</span><div class="cf-author-details"><div class="cf-source">Kettle &amp; Kind</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer36"><![CDATA[<div class="cf-offer"><div class="cf-domain">kettleandkind.example</div><div class="cf-offer-title">Two blends. One better morning.</div><div class="cf-offer-detail">Morning Duo · $24</div></div>]]></res>
  <res label="copy37">Running low on the good coffee? Take 20% off your first coffee order with HELLO20. Pick your blend, choose your grind, put the kettle on.</res>
  <res label="byline37"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-2" aria-hidden="true">K&amp;K</span><div class="cf-author-details"><div class="cf-source">Kettle &amp; Kind</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer37"><![CDATA[<div class="cf-offer"><div class="cf-domain">kettleandkind.example</div><div class="cf-offer-title">A fresh start for your coffee shelf</div><div class="cf-offer-detail">20% off first order</div></div>]]></res>
  <res label="copy38">Coffee worth making time for. Discover our House Blend and Weekend Roast. Free shipping when you choose any three bags.</res>
  <res label="byline38"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-2" aria-hidden="true">K&amp;K</span><div class="cf-author-details"><div class="cf-source">Kettle &amp; Kind</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer38"><![CDATA[<div class="cf-offer"><div class="cf-domain">kettleandkind.example</div><div class="cf-offer-title">Your next favorite cup</div><div class="cf-offer-detail">Free shipping on 3 bags</div></div>]]></res>
  <res label="copy39">A little green goes a long way. Our ceramic windowsill planters have a drainage hole and matching saucer. Starting at $24. Plant not included.</res>
  <res label="byline39"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-3" aria-hidden="true">L</span><div class="cf-author-details"><div class="cf-source">Leafline Studio</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer39"><![CDATA[<div class="cf-offer"><div class="cf-domain">leaflinestudio.example</div><div class="cf-offer-title">Small pots. Happier corners.</div><div class="cf-offer-detail">Ceramic planters · From $24</div></div>]]></res>
  <res label="copy40">Give your favorite plant a fresh home. Meet the Everyday Planter in sage, cream and terracotta. Buy two and save 15%. Plants not included.</res>
  <res label="byline40"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-3" aria-hidden="true">L</span><div class="cf-author-details"><div class="cf-source">Leafline Studio</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer40"><![CDATA[<div class="cf-offer"><div class="cf-domain">leaflinestudio.example</div><div class="cf-offer-title">Room to grow</div><div class="cf-offer-detail">Save 15% when you buy 2</div></div>]]></res>
  <res label="copy41">That sunny corner is missing something. Add a ceramic planter in a color that feels like home. Free shipping on orders over $45.</res>
  <res label="byline41"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-3" aria-hidden="true">L</span><div class="cf-author-details"><div class="cf-source">Leafline Studio</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer41"><![CDATA[<div class="cf-offer"><div class="cf-domain">leaflinestudio.example</div><div class="cf-offer-title">Find your windowsill favorite</div><div class="cf-offer-detail">From $24 · Free shipping over $45</div></div>]]></res>
  <res label="copy42">Simple shapes. Soft colors. A proper drainage hole. Discover our Everyday Planter collection and take 10% off your first order with GROW10.</res>
  <res label="byline42"><![CDATA[<div class="cf-author-row"><span class="cf-avatar cf-brand-avatar cf-brand-3" aria-hidden="true">L</span><div class="cf-author-details"><div class="cf-source">Leafline Studio</div><div class="cf-post-meta"><span>Sponsored</span><span aria-hidden="true"> · </span><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.3" fill="currentColor"/><path d="M5 2.8l.8 2.4-1.4 2.1 2.5.9.8 3.3 1.4 1.2 1.4-2.3-.5-2.4 2.4-1.5-2.1-1.3L9 2" fill="white"/></svg></div></div></div>]]></res>
  <res label="offer42"><![CDATA[<div class="cf-offer"><div class="cf-domain">leaflinestudio.example</div><div class="cf-offer-title">A fresh home for your plants</div><div class="cf-offer-detail">10% off your first order</div></div>]]></res>
  <res label="image1"><![CDATA[<img data-src="[rel image-01.jpg]" alt="Coffee, a croissant and an open book on a kitchen table" width="800" height="600" decoding="async"/>]]></res>
  <res label="image2"><![CDATA[<img data-src="[rel image-02.jpg]" alt="A coastal walking path above the sea" width="800" height="600" decoding="async"/>]]></res>
  <res label="image3"><![CDATA[<img data-src="[rel image-03.jpg]" alt="Colorful front doors and gardens on a quiet street" width="800" height="600" decoding="async"/>]]></res>
  <res label="image4"><![CDATA[<img data-src="[rel image-04.jpg]" alt="Small boats in a harbor at low tide" width="800" height="600" decoding="async"/>]]></res>
  <res label="image5"><![CDATA[<img data-src="[rel image-05.jpg]" alt="Basil and mint growing on a kitchen windowsill" width="800" height="600" decoding="async"/>]]></res>
  <res label="image6"><![CDATA[<img data-src="[rel image-06.jpg]" alt="Paperbacks and a cup of tea on a sofa" width="800" height="600" decoding="async"/>]]></res>
  <res label="image7"><![CDATA[<img data-src="[rel image-07.jpg]" alt="A watercolor painting in progress on a dining table" width="800" height="600" decoding="async"/>]]></res>
  <res label="image8"><![CDATA[<img data-src="[rel image-08.jpg]" alt="Bread, cheese and pears at a picnic in the park" width="800" height="600" decoding="async"/>]]></res>
  <res label="image9"><![CDATA[<img data-src="[rel image-09.jpg]" alt="A freshly baked loaf on a wooden kitchen board" width="800" height="600" decoding="async"/>]]></res>
  <res label="image10"><![CDATA[<img data-src="[rel image-10.jpg]" alt="A bicycle beside a leafy riverside path" width="800" height="600" decoding="async"/>]]></res>
  <res label="image11"><![CDATA[<img data-src="[rel image-11.jpg]" alt="A forest-green everyday backpack on a trail-side bench" width="800" height="600" decoding="async"/>]]></res>
  <res label="image12"><![CDATA[<img data-src="[rel image-12.jpg]" alt="A slate everyday backpack with daily essentials" width="800" height="600" decoding="async"/>]]></res>
  <res label="image13"><![CDATA[<img data-src="[rel image-13.jpg]" alt="A bag of coffee and a freshly poured cup on a counter" width="800" height="600" decoding="async"/>]]></res>
  <res label="image14"><![CDATA[<img data-src="[rel image-14.jpg]" alt="Coffee beans, a pour-over brewer and a ceramic mug" width="800" height="600" decoding="async"/>]]></res>
  <res label="image15"><![CDATA[<img data-src="[rel image-15.jpg]" alt="Sage and cream ceramic planters with houseplants" width="800" height="600" decoding="async"/>]]></res>
  <res label="image16"><![CDATA[<img data-src="[rel image-16.jpg]" alt="Terracotta and sage planters in a sunny home" width="800" height="600" decoding="async"/>]]></res>
  <number label="DesignVersion" where="execute" size="3">
    <title>Assigned .dat design version</title>
    <exec>
if DesignVersion.val is None:
    DesignVersion.val = random.randint(1,8)
</exec>
  </number>
  <number label="DesignRevision" where="execute" size="2">
    <title>Design and timing schema revision</title>
    <exec>DesignRevision.val = 5</exec>
  </number>
  <number label="ExposureRevision" where="execute" size="2">
    <title>Full-card exposure schema revision</title>
    <exec>ExposureRevision.val = 1</exec>
  </number>
  <number label="SessionKey" where="execute" size="12">
    <title>Anonymous response cache key</title>
    <exec>
if SessionKey.val is None:
    SessionKey.val = random.randint(100000000,999999999)
</exec>
  </number>
  <html label="Initialize" where="survey"><![CDATA[<div class="cf-init" role="status"><div class="cf-round">Feed 1 of 5</div><h2>Like the posts that stand out to you</h2><p>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</p><div class="cf-skeleton" aria-label="Preparing feed"></div></div>]]></html>
  <suspend />
  <number label="Offer1" where="execute" optional="1" size="6">
    <title>Feed 1: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,1,i)]
    r = Offer1.rows[i-1]
    r.task.val = 1
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>
  <number label="Time1" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time1.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>
  <html label="Header1" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="1" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed1"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 1 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,1,i)]
    Feed1.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />
  <number label="Offer2" where="execute" optional="1" size="6">
    <title>Feed 2: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,2,i)]
    r = Offer2.rows[i-1]
    r.task.val = 2
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>
  <number label="Time2" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time2.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>
  <html label="Header2" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="2" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed2"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 2 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,2,i)]
    Feed2.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />
  <number label="Offer3" where="execute" optional="1" size="6">
    <title>Feed 3: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,3,i)]
    r = Offer3.rows[i-1]
    r.task.val = 3
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>
  <number label="Time3" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time3.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>
  <html label="Header3" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="3" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed3"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 3 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,3,i)]
    Feed3.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />
  <number label="Offer4" where="execute" optional="1" size="6">
    <title>Feed 4: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,4,i)]
    r = Offer4.rows[i-1]
    r.task.val = 4
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>
  <number label="Time4" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time4.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>
  <html label="Header4" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="4" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed4"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 4 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,4,i)]
    Feed4.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />
  <number label="Offer5" where="execute" optional="1" size="6">
    <title>Feed 5: assigned design metadata by display position</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="task">Feed task</col>
    <col label="item">Item identity</col>
    <col label="order">Display order</col>
    <col label="copy">Copy level</col>
    <col label="image">Image level</col>
    <col label="kind">0 organic; 1 sponsored</col>
    <col label="creative">Creative identity; 0 organic</col>
    <col label="campaign">Campaign identity; 0 organic</col>
    <col label="context">Feed context identity</col>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,5,i)]
    r = Offer5.rows[i-1]
    r.task.val = 5
    r.item.val = a[3]
    r.order.val = a[2]
    r.copy.val = a[0]
    r.image.val = a[1]
    r.kind.val = a[4]
    r.creative.val = a[5]
    r.campaign.val = a[6]
    r.context.val = a[7]
</exec>
  </number>
  <number label="Time5" optional="1" size="12" ss:questionClassNames="cf-timing">
    <title>Visible time measurement</title>
    <row label="r1">Position 1</row>
    <row label="r2">Position 2</row>
    <row label="r3">Position 3</row>
    <row label="r4">Position 4</row>
    <row label="r5">Position 5</row>
    <row label="r6">Position 6</row>
    <row label="r7">Position 7</row>
    <row label="r8">Position 8</row>
    <row label="r9">Position 9</row>
    <row label="r10">Position 10</row>
    <row label="r11">Position 11</row>
    <row label="r12">Position 12</row>
    <row label="r13">Position 13</row>
    <row label="r14">Position 14</row>
    <row label="r15">Position 15</row>
    <row label="r16">Position 16</row>
    <row label="r17">Position 17</row>
    <row label="r18">Position 18</row>
    <row label="r19">Position 19</row>
    <row label="r20">Position 20</row>
    <col label="ms">Visible milliseconds</col>
    <col label="state">Legacy measurement state</col>
    <col label="anyms">Cumulative milliseconds at least 1 percent full card visible</col>
    <col label="halfms">Cumulative milliseconds at least 50 percent full card visible</col>
    <col label="exposurestate">Full-card exposure measurement state</col>
    <exec>
for r in Time5.rows:
    if r.ms.val is None: r.ms.val = -1
    if r.state.val is None: r.state.val = 0
    if r.anyms.val is None: r.anyms.val = -1
    if r.halfms.val is None: r.halfms.val = -1
    if r.exposurestate.val is None: r.exposurestate.val = 0
</exec>
  </number>
  <html label="Header5" where="survey"><![CDATA[<div class="cf-config" data-revision="5" data-feed="5" data-feeds="5" data-version="${DesignVersion.val}" data-session="${SessionKey.val}"></div>]]></html>
  <radio
    label="Feed5"
    type="rating"
    optional="0"
    ss:questionClassNames="cf-feed"
    ss:accordionDisplay="0"
  >
    <title><![CDATA[<span class="cf-round">Feed 5 of 5</span>Like the posts that stand out to you]]></title>
    <comment>Browse the feed and tap Like, or double-tap an image. Tap again to undo. It’s fine to leave a feed without liking anything.</comment>
    <exec>
for i in range(1,21):
    a = socialDesign[(DesignVersion.val,5,i)]
    Feed5.rows[i-1].text = '%s&lt;p class="cf-copy"&gt;%s&lt;/p&gt;&lt;div class="cf-art"&gt;%s&lt;/div&gt;%s' % (res["byline%d" % a[0]], res["copy%d" % a[0]], res["image%d" % a[1]], res["offer%d" % a[0]])
</exec>
    <row label="r1">Item 1</row>
    <row label="r2">Item 2</row>
    <row label="r3">Item 3</row>
    <row label="r4">Item 4</row>
    <row label="r5">Item 5</row>
    <row label="r6">Item 6</row>
    <row label="r7">Item 7</row>
    <row label="r8">Item 8</row>
    <row label="r9">Item 9</row>
    <row label="r10">Item 10</row>
    <row label="r11">Item 11</row>
    <row label="r12">Item 12</row>
    <row label="r13">Item 13</row>
    <row label="r14">Item 14</row>
    <row label="r15">Item 15</row>
    <row label="r16">Item 16</row>
    <row label="r17">Item 17</row>
    <row label="r18">Item 18</row>
    <row label="r19">Item 19</row>
    <row label="r20">Item 20</row>
    <col label="c1" value="1">Not exposed under rule</col>
    <col label="c2" value="2">Exposed, not liked</col>
    <col label="c3" value="3">Liked</col>
  </radio>
  <suspend />
  <samplesources default="0">
    <samplesource list="0">
      <title>Open survey</title>
      <completed>You have already completed this study.</completed>
      <exit cond="qualified">Your responses have been recorded.</exit>
    </samplesource>
  </samplesources>
  <!-- questra-theme:start -->
  <style name="survey.completion"><![CDATA[]]></style>
  <style name="survey.respview.footer" mode="after"><![CDATA[<footer class="qt-footer"><img src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjAwIiBoZWlnaHQ9IjQ4MCIgdmlld0JveD0iMCAwIDE2MDAgNDgwIj48cGF0aCBkPSJNMTE1Ni4wNSwzMDAuNDFjLTM0LjgyLDQwLjQtNzIuNzUsNzIuNjYtMTE1LjM4LDk4LjU0LTg2Ljk0LDUyLjc3LTE5My42OCw3OC40Mi0zMjYuMTcsNzguNDJzLTIzOS4yOC0yNS42NS0zMjYuMjItNzguNDJjLTQ0LjQtMjYuOTQtODMuNjYtNjAuNzMtMTE5LjY4LTEwMy41MywxNC4yNS00LjkzLDI3LjMyLTExLjk2LDM4Ljg1LTIwLjc5LDc3LjM4LDg4LjQyLDE5NS4zMywxNTkuNTgsNDA3LjA1LDE1OS41OCwxOTYuOTUsMCwzMTIuNzgtNjEuNiwzOTAuMjMtMTQxLjM3LDExLjExLDUuMzUsMjQuMzIsOC4yNywzOS4xLDguMjcsNC4yMSwwLDguMjktLjIzLDEyLjIxLS43WiIgZmlsbD0iIzEwMzc0MyIvPjxwYXRoIGQ9Ik0zOTIuNDMsMjA2LjY1Vjc4LjQyaDQ0LjE5djExNS4yMWMwLDI4LjgsMTguNTQsNDguMTQsNDYuOTUsNDguMTQsMjkuOTksMCw1MC4xMS0xOS43Myw1MC4xMS00OC45M3YtMTE0LjQyaDQ0LjE5djE0MC4wN2MwLDExLjQ0LDcuMSwxOC41NCwxOC41NCwxOC41NGgzLjk0djQyLjYxaC0xMy4wMmMtMjYuNDMsMC00My40LTEwLjI2LTUwLjExLTI5LjItMTUuMzksMjIuMS0zOC42NywzMy45My02Ny44NywzMy45My00Ni4xNiwwLTc2Ljk0LTMwLjc4LTc2Ljk0LTc3LjczWiIgZmlsbD0iIzEwMzc0MyIvPjxwYXRoIGQ9Ik02MTguMjIsMTc5LjAzYzAtNTkuOTcsNDYuMTYtMTA1LjM1LDEwNy4zMy0xMDUuMzVzMTA3LjcyLDQ1LjM4LDEwNy43MiwxMDUuNzVjMCw1LjUyLS40LDExLjQ0LTEuMTksMTYuNTdoLTE2Ni41MWM2LjcxLDI5LjIsMzAuMzgsNDguNTMsNjEuOTUsNDguNTMsMjMuMjgsMCw0My40LTEwLjI2LDUzLjY2LTI1LjY1aDQ4LjkzYy0xNi4xOCwzOS4wNi01NS42Myw2NS41LTEwMy4zOCw2NS41LTYyLjM0LDAtMTA4LjUxLTQ1LjM3LTEwOC41MS0xMDUuMzVaTTY2NS45NiwxNTkuN2gxMTkuOTVjLTYuNzEtMjcuNjItMzAuMzgtNDYuMTYtNjAuMzctNDYuMTZzLTUyLjQ4LDE4LjE1LTU5LjU4LDQ2LjE2WiIgZmlsbD0iIzEwMzc0MyIvPjxwYXRoIGQ9Ik04NjAuMDYsMjIwLjQ2aDQ0Ljk4YzAsMTUuMzksMTQuNiwyNS42NSwzNS45MSwyNS42NSwxOS43MywwLDMyLjc0LTkuMDgsMzIuNzQtMjEuNywwLTM2LjMtMTEwLjQ3LTE2LjE4LTExMC40Ny04Ny41OSwwLTM5LjA2LDMxLjE3LTYzLjEzLDc1Ljc2LTYzLjEzczc2LjU1LDI0Ljg2LDc2LjU1LDYxLjE2aC00NC45OGMwLTEzLjgxLTEzLjAyLTIzLjI4LTMxLjk2LTIzLjI4cy0zMC43Nyw4LjI5LTMwLjc3LDIwLjUyYzAsMzUuMTEsMTEwLjg3LDE1Ljc4LDExMC44Nyw4Ny41OSwwLDM5LjA2LTMxLjE3LDY0LjcxLTc4LjEyLDY0Ljcxcy04MC40OS0yNi4wNC04MC40OS02My45MloiIGZpbGw9IiMxMDM3NDMiLz48cGF0aCBkPSJNMTIzOC41Nyw3OC40Mmg0NC4xOXYzMy41NGMxNS43OS0yMi44OCwzOS4wNi0zNi42OSw2Ny40Ny0zNi42OWg3LjF2NDUuMzdoLTcuMWMtNDIuNjIsMC02Ny40NywyNC4wNy02Ny40Nyw2MS4xNnY5Ny44NWgtNDQuMTlWNzguNDJaIiBmaWxsPSIjMTAzNzQzIi8+PHBhdGggZD0iTTEzNjQuMDUsMTc5LjAzYzAtNTkuOTcsNDIuMjItMTA1LjM1LDk5LjAzLTEwNS4zNSwyOS42LDAsNTQuMDYsMTIuNjMsNzAuNjMsMzMuNTR2LTI4LjhoNDQuMTl2MTQwLjA3YzAsMTEuNDQsNi43MSwxOC41NCwxOC41NCwxOC41NGgzLjU1djQyLjYxaC0xMi42M2MtMjcuNjIsMC00NC45OC0xMS4wNS01MC45LTMxLjk2LTE2Ljk3LDIyLjg5LTQyLjYyLDM2LjctNzMuNCwzNi43LTU2LjgxLDAtOTkuMDMtNDUuMzctOTkuMDMtMTA1LjM1Wk0xNTMzLjcxLDE3OS4wM2MwLTM1LjUxLTI2LjQzLTYyLjc0LTYxLjk0LTYyLjc0cy02Mi4zNCwyNy4yMi02Mi4zNCw2Mi43NCwyNi40NCw2Mi43NCw2Mi4zNCw2Mi43NCw2MS45NC0yNy4yMiw2MS45NC02Mi43NFoiIGZpbGw9IiMxMDM3NDMiLz48cGF0aCBkPSJNMTQ0LjI2LDgxLjg3Yy01Ljk4LDcuMzQtMTAuOTEsMTUuNi0xNC40MywyNC42Nkg0OS4zN3YtMjQuNjZoOTQuODlaIiBmaWxsPSIjZmY1MDVkIi8+PHJlY3QgeT0iODEuODUiIHdpZHRoPSIyNC42NyIgaGVpZ2h0PSIyNC42NyIgZmlsbD0iI2ZmNTA1ZCIvPjxwYXRoIGQ9Ik0xMjIuOTIsMTQzLjUyYzAsNC4xOS4yNSw4LjMyLjc0LDEyLjMzaC00OS42M3YtMjQuNjZoNDkuNjNjLS40OSw0LjAxLS43NCw4LjE0LS43NCwxMi4zM1oiIGZpbGw9IiNmZjUwNWQiLz48cGF0aCBkPSJNMTQ0LjI2LDIwNS4xOEg0OS4zN3YtMjQuNjZoODAuNDZjMy41MSw5LjA2LDguNDUsMTcuMzMsMTQuNDMsMjQuNjZaIiBmaWxsPSIjZmY1MDVkIi8+PHJlY3QgeD0iMjQuNjciIHk9IjEzMS4xOSIgd2lkdGg9IjI0LjY3IiBoZWlnaHQ9IjI0LjY3IiBmaWxsPSIjZmY1MDVkIi8+PHJlY3QgeT0iMTgwLjUzIiB3aWR0aD0iMjQuNjciIGhlaWdodD0iMjQuNjciIGZpbGw9IiNmZjUwNWQiLz48cGF0aCBkPSJNMTA3Ni43NSwyMjEuMjV2LTEwMi41OWgtMzMuOTN2LTQwLjI0aDIwLjUxYzEwLjI2LDAsMTUuNzktNS41MiwxNS43OS0xNS43OFYyMy45N2g0MS44MnY1NC40NWg2NS44OXY0MC4yNGgtNjUuODl2OTguMjVjMCwxMy40MSw5LjA4LDIyLjEsMjIuODksMjIuMXMyMi44OS05LjQ3LDIyLjg5LTI1LjI1aDM5LjQ2YzAsNDAuMjQtMjUuMjUsNjUuODktNjUuNSw2NS44OXMtNjMuOTItMjMuMjgtNjMuOTItNTguNFoiIGZpbGw9IiMxMDM3NDMiLz48cGF0aCBkPSJNMzYxLjA0LDE0Mi43MmMwLDgwLjA5LTYxLjU0LDE0MC4wMi0xNDMuMjMsMTQwLjAyLTQ2Ljk4LDAtODcuNDktMjAuMjktMTEzLjMyLTUyLjloNzEuNThjMTIuNDUsNS45MiwyNi42NCw5LjE4LDQxLjc0LDkuMTgsMS45OSwwLDMuOTYtLjA2LDUuOTEtLjE3LTcuMDgtMTAuNjctMTMuOTktMjEuNzItMjEuMDYtMzMuNjhsMzcuMTgtMjIuMDFjOC42NywxNC42NywxNy40OSwyOC43MSwyNy4yNCw0Mi44NiwyNy44Ni0xNi4yNyw0NS44Ny00Ni40NSw0NS44Ny04Mi41LDAtNTQuNDQtNDEuMDctOTUuNTEtOTUuMTQtOTUuNTEtMTUuMSwwLTI5LjI5LDMuMjctNDEuNzQsOS4xOWgtNzMuNjhDMTI4LjEsMjMuNDcsMTY5LjUzLDIuNjMsMjE3LjgxLDIuNjNjODEuNjksMCwxNDMuMjMsNjAsMTQzLjIzLDE0MC4wOVoiIGZpbGw9IiMxMDM3NDMiLz48L3N2Zz4=" data-brand-source="https://www.questra.ai/logo/primary/full-color.svg" alt="Questra" width="120" height="36" decoding="async" /></footer>]]></style>
  <!-- questra-theme:end -->
</survey>

See how Questra fits your survey workflow.

Book a demo