/* Homepage variant styles, moved out of index.html so the page carries text, not CSS.
   Edit here, not in the HTML. */
  /* Every token is in /site.css. This page adds none. */
  *{box-sizing:border-box;margin:0;padding:0}
  html{background:var(--bg)}
  body{background:var(--bg);color:var(--ink);font-family:var(--display);line-height:1.5;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
  a{color:inherit}
  .wrap{width:min(92vw,var(--w));margin:0 auto;padding:0 var(--gut)}
  section{border-top:1px solid var(--line)}
  .sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

  /* buttons: /site.css owns the shape. Only the icon size is local. */
  .btn svg{width:14px;height:14px}

  /* hero */
  .hero{border-top:0;padding:clamp(44px,6vh,76px) 0 clamp(48px,7vh,76px);text-align:center;position:relative;overflow:hidden}
  /* Anchored in px, not in a percentage of the hero's own height: the hero is
     taller now that it carries the ask card, and top:-40% dragged the glow up
     off it. .hero is overflow:hidden, so this is also what keeps the glow from
     being clipped against a box that now sits lower. */
  .hero::before{content:"";position:absolute;left:50%;top:-150px;width:1200px;height:820px;transform:translateX(-50%);background:radial-gradient(closest-side,rgba(248,164,52,.14),rgba(248,164,52,0));pointer-events:none}
  .hero .wrap{position:relative}
  .hero h1{font-size:clamp(40px,7vw,84px);font-weight:600;letter-spacing:-.04em;line-height:1.02;max-width:12em;margin:0 auto}
  /* block, so the headline always locks as two lines: the role title over the
     tail. Without it the break moves with the viewport and the rule below can
     land mid-phrase next to "on your". */
  .hero h1 b{display:block;font-weight:600;color:var(--muted)}
  /* The role title is the claim, so it gets marked - not filled. An amber
     phrase at 84px would put most of the headline in the accent and compete
     with the one amber button beneath it; the accent's job here is the button.
     var(--grad) is the brand token, not a new ramp. clone gives a wrapped
     phrase a rule per line, which is what happens at 480px and below. */
  .hero h1 .role{background-image:var(--grad);background-repeat:no-repeat;
    background-size:100% 3px;background-position:0 calc(100% - .06em);
    -webkit-box-decoration-break:clone;box-decoration-break:clone;padding-bottom:.12em}
  .hero .lede{font-size:clamp(17px,2vw,20px);font-weight:400;color:var(--muted);max-width:40em;margin:20px auto 0;text-wrap:pretty}

  /* The home page's ask card sits inside the hero, so it takes the hero's
     centring and adds only what the catalog card does not have: a visible
     <label> above the textarea (a placeholder vanishes on the first keystroke,
     which is when someone is least sure they are doing the right thing). */
  .ask-card.home{max-width:980px;margin:28px auto 0;text-align:left}
  .ask-card.home .ask-label{display:block;font-size:17px;font-weight:600;letter-spacing:-.012em;color:var(--ink);line-height:1.35;margin-bottom:14px}
  /* Air between the five stacked things in this door (Fred, 2026-09-19: "feels
     crowded"): label to box, box to nudge, nudge to button. Element-qualified
     selectors because .ask-card p.ask-nudge (0,2,1) and .ask-card .ask-label
     (0,2,0) are the rules being overridden. */
  .ask-card.home p.ask-nudge{margin-top:14px}
  /* 18, the same as the agent door's button and the same as the panel
     padding under it, so an action has equal room above and below
     wherever it sits (Fred, 2026-09-19). One value, every width. */
  .ask-card.home .ask-form .btn{margin-top:18px}
  /* The composer's size, the iOS 16px floor and the Build it button all live
     in /site.css now, with the rest of the .ask-* family. Local copies here
     drifted from it: the 16px fix reached this page and no catalog page, and
     .ask-card.home .btn (0,3,0) beat .ask-doors .btn, so between 561 and
     859px the home button was a pill where every other card stretched. */

  /* THE APP BAND. Texture and proof of breadth under the two doors, not a
     third CTA: knocked back at rest, full colour on hover, one link to /apps.
     Every tile is a link to its own app page; the head's "Browse the catalog"
     is the link to /apps. Loop copies are out of the tab order and a11y tree.
     109 slugs over six rows: the featured list, then the rest of the catalog's
     recognisable names. Ten rows were tried on 2026-09-21 and cut back the same
     day (Fred: "6 rows is plenty"); the sixth row is the eighteen most
     recognisable names of the ninety that passed the logo check that day. Every logo is md5-hashed and pixel-sampled against
     this tile's white img background before it goes in. Re-run that check
     before adding a tile - the feed's logos change.

     What the check has caught so far, both passes verified against catalog/v1
     (2026-09-17, re-run 2026-09-21 over 231 logos):
       Identical bytes, so only the first of each pair is here - Twilio and
       SendGrid; gmail, Google Calendar, Google Analytics and Google Tasks;
       PagerDuty and PagerDuty Events API; Freshdesk and Freshworks CRM.
       (The other Google logos are distinct and are here.)
       White ink that vanishes on a white tile, so none of these are here -
       Anthropic, Uploadcare and Hex. The test is the share of pixels below
       200 luminance once the logo is composited on white: these three are
       at zero, where the darkest tile that IS here sits at .054.
       Same brand twice, which reads as a bug - HubSpot Enterprise and
       Smartsheet via API Token are out, HubSpot and Smartsheet are in. */
  .apps{background:var(--bg-2);padding:clamp(28px,3.6vw,40px) 0}
  .apps-head{display:flex;align-items:baseline;justify-content:space-between;gap:16px;
    width:min(92vw,var(--w));margin:0 auto clamp(16px,1.6vw,22px);padding:0 var(--gut)}
  .apps-head .k{font-family:var(--mono);font-size:12px;letter-spacing:.14em;
    text-transform:uppercase;color:var(--label)}
  .apps-head .go{font-family:var(--mono);font-size:12px;letter-spacing:.06em;
    color:var(--muted);white-space:nowrap;transition:color .2s}
  .apps-head .go{text-decoration:none}
  .apps-head .go:hover,.apps-head .go:focus-visible{color:var(--ink)}
  .apl{display:block;flex:none;text-decoration:none;color:inherit;border-radius:12px}
  .apl:focus-visible{outline:2px solid var(--v2);outline-offset:3px}
  /* The band fills the viewport: on a wide display the ribbon used to sit in a
     1760px box with dark margins either side (Fred, 2026-09-21: "if stretched
     wide, we should fill in with icons"). A seamless loop needs
     maxRowWidth <= (runs-1) x runWidth, and the shortest run is 18 tiles x
     58px = 1044, so FOUR runs cover 3132 and the cap is 3100. Change the tile
     count or the run count and re-check this inequality; the keyframe below
     translates by -100%/4 for the same reason. */
  /* Wide dissolve: 34% each side, capped at 460px so a 2500px display still
     shows icons across most of its width rather than a faded middle third. Was
     22% and uncapped; Fred asked for the fade to be more pronounced and the
     band to fill wide screens (2026-09-21). */
  .aprows{max-width:3100px;margin-inline:auto;overflow:hidden;
    -webkit-mask-image:linear-gradient(90deg,transparent,#000 min(34%,460px),#000 calc(100% - min(34%,460px)),transparent);
    mask-image:linear-gradient(90deg,transparent,#000 min(34%,460px),#000 calc(100% - min(34%,460px)),transparent);
    -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}
  /* NO flex gap. Spacing is margin-right on the tile, so a run's own width
     already includes its trailing gap and lineWidth == 4 x runWidth exactly,
     which is what makes translate(-100%/4) land on the seam. With `gap`
     between the runs the loop drifts by gap/4 every cycle. */
  .apline{display:flex;width:max-content;will-change:transform;
    animation:apdrift 34s linear infinite}
  .aprun{display:flex;flex:none}
  .apline+.apline{margin-top:14px}
  /* Held back at rest, but warm: the icons sit in the brand amber (grayscale,
     then sepia pushed towards --v1) so the band reads as texture in the page's
     own palette rather than a row of app-store icons. Hover brings the band to
     full colour, which is the moment it becomes a link. */
  .apl{margin-right:14px}
  .apline .tile{opacity:.7;
    filter:grayscale(1) sepia(.3) saturate(1.2) hue-rotate(-20deg) brightness(.95);
    transition:opacity .45s,filter .45s}
  /* Six speeds, every even row reversed, so the rows never lock step and no two
     tiles ever stack vertically for long. Every duration here is distinct; two
     rows sharing one would drift together and read as a block. A row with no
     rule falls back to the 34s in .apline and drifts in step with row 1: add a
     duration whenever you add a row. */
  .aprows .apline:nth-child(1){animation-duration:34s}
  .aprows .apline:nth-child(2){animation-duration:38s;animation-direction:reverse}
  .aprows .apline:nth-child(3){animation-duration:30s}
  .aprows .apline:nth-child(4){animation-duration:42s;animation-direction:reverse}
  .aprows .apline:nth-child(5){animation-duration:26s}
  .aprows .apline:nth-child(6){animation-duration:40s;animation-direction:reverse}
  @keyframes apdrift{from{transform:translate3d(0,0,0)}to{transform:translate3d(calc(-100% / 4),0,0)}}
  /* Pause on hover so a drifting 44px target holds still long enough to click;
     the band lifts halfway, the tile under the pointer goes to full colour. */
  .aprows:hover .apline{animation-play-state:paused}
  .aprows:hover .tile{opacity:.85;filter:grayscale(.5) sepia(.15) saturate(1.15) hue-rotate(-14deg)}
  .apl:hover .tile,.apl:focus-visible .tile{opacity:1;filter:none}
  /* The app's name, on dwell. It appears only when the pointer STOPS (Fred,
     2026-09-19): every move of more than a few pixels restarts the timer, so
     sweeping across the band shows nothing and resting on one tile names it.
     Position is read ONCE, at show time, which is only correct because the
     band is already paused under the pointer by the rule above. If that pause
     ever goes, this has to track the tile instead. */
  .aptip{position:fixed;left:0;top:0;z-index:60;pointer-events:none;
    padding:6px 10px;border-radius:9px;border:1px solid var(--line-2);
    background:rgba(19,19,21,.98);color:var(--ink);
    font-family:var(--display);font-size:12.5px;font-weight:500;line-height:1.2;
    white-space:nowrap;box-shadow:0 6px 22px rgba(0,0,0,.5);
    opacity:0;transform:translate(-50%,calc(-100% - 2px));
    transition:opacity .16s ease-out,transform .16s ease-out}
  .aptip.on{opacity:1;transform:translate(-50%,calc(-100% - 10px))}
  .aptip::after{content:"";position:absolute;left:50%;bottom:-4px;width:7px;height:7px;
    margin-left:-3.5px;transform:rotate(45deg);background:rgba(19,19,21,.98);
    border-right:1px solid var(--line-2);border-bottom:1px solid var(--line-2)}
  @media (prefers-reduced-motion:reduce){
    .aptip{transition:opacity .01s linear;transform:translate(-50%,calc(-100% - 10px))}}
  @media (max-width:640px){.apps-head{display:block}.apps-head .go{margin-top:6px}}
  @media (max-width:560px){
    .apline .tile.sm{width:38px;height:38px;border-radius:10px}.apl{margin-right:12px}
    .apline+.apline{margin-top:12px}
  }
  /* A hard stop is safe here: at t=0 the line sits at translate 0, a complete
     row, and three runs cover the widest viewport from that position. A user
     who set this preference asked for motion to stop, not to slow. */
  @media (prefers-reduced-motion:reduce){.apline{animation:none}}

  /* section furniture */
  .sec{padding:clamp(64px,9vh,112px) 0}
  .eyebrow{font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--label);margin-bottom:14px}
  h2{font-size:clamp(28px,4vw,44px);font-weight:600;letter-spacing:-.03em;line-height:1.08;max-width:18em;text-wrap:balance}
  .sub{font-size:clamp(16px,1.6vw,19px);color:var(--muted);max-width:36em;margin-top:16px;text-wrap:pretty}

  /* bordered grid */
  .grid{display:grid;grid-template-columns:repeat(3,1fr);border:1px solid var(--line);border-radius:14px;overflow:hidden;background:var(--bg-2);margin-top:44px}
  .grid > div{padding:28px 26px;border-right:1px solid var(--line);border-bottom:1px solid var(--line)}
  .grid > div:nth-child(3n){border-right:0}
  .grid > div:nth-last-child(-n+3){border-bottom:0}
  .grid h3{font-size:18px;font-weight:600;letter-spacing:-.01em;margin-bottom:8px}
  .grid p{font-size:15px;color:var(--muted)}
  .grid .k{font-family:var(--mono);font-size:12px;color:var(--label);letter-spacing:.06em;margin-bottom:14px}
  /* display:flex and the meter's own rules live in /site.css: home.html
     defines a different .prims and would drop them on the launch swap. */

  /* two-up */
  .two{margin-top:32px}
  .two p{color:var(--muted);font-size:17px;margin-top:14px;max-width:44em}
  .two ul{list-style:none;margin-top:22px;max-width:52em}
  .two li{padding:12px 0;border-top:1px solid var(--line);font-size:16px;display:flex;gap:12px;align-items:baseline}
  .two li:last-child{border-bottom:1px solid var(--line)}
  .two li svg{width:14px;height:14px;flex:none;position:relative;top:1px;color:var(--v1)}

  /* primitives */
  .prims{display:grid;grid-template-columns:repeat(4,1fr);gap:0;border:1px solid var(--line);border-radius:14px;overflow:hidden;background:var(--bg-2);margin-top:44px}
  .prims div{padding:22px 24px;border-right:1px solid var(--line);border-bottom:1px solid var(--line);font-size:16px;font-weight:500}
  .prims div span{display:block;font-size:14px;font-weight:400;color:var(--muted);margin-top:4px}
  .prims div:nth-child(4n){border-right:0}
  .prims div:nth-last-child(-n+4){border-bottom:0}

  /* enterprise + close */
  .ent{background:var(--bg-2)}
  .ent h2{color:var(--ink)}
  .ent .sub{color:var(--muted)}
  /* .ent no longer uses .row. It was a statement plus a ghost button and it
     read flat between the icon grid above and the reviews widget below (Fred,
     2026-09-21). The band now carries a panel: the audience strip, the four
     things a dedicated instance adds, the action, and one drawing. */
  .ent-card{margin-top:clamp(28px,3.4vw,40px);border:1px solid var(--line);
    border-radius:14px;background:var(--bg);overflow:hidden}
  /* The audience line used to be the last clause of the paragraph. It is the
     panel's header strip now: its own row, its own rule under it, three names
     at body weight, each marked with an amber node. Not chips - a bordered
     pill here would read as a filter control. */
  .ent-who{display:flex;flex-wrap:wrap;align-items:center;gap:10px 26px;
    padding:15px 26px;border-bottom:1px solid var(--line)}
  .ent-who .k{font-family:var(--mono);font-size:12px;letter-spacing:.14em;
    text-transform:uppercase;color:var(--label)}
  .ent-who .who{display:inline-flex;align-items:center;gap:9px;font-size:15px;
    font-weight:600;letter-spacing:-.01em;color:var(--ink)}
  .ent-who .who::before{content:"";width:6px;height:6px;border-radius:50%;
    background:var(--v1);flex:none}
  .ent-body{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,300px);
    gap:clamp(24px,3vw,44px);align-items:center;padding:clamp(22px,2.6vw,30px) 26px}
  .ent-adds .k{font-family:var(--mono);font-size:12px;letter-spacing:.14em;
    text-transform:uppercase;color:var(--label);margin-bottom:8px}
  .ent-adds ul{list-style:none}
  /* Same list furniture as .two: hairline per row, 14px accent mark, baseline
     aligned. A plus, not the check .two uses - these are additions to what the
     reader already has, and the two lists are eight rows apart on the page. */
  .ent-adds li{display:flex;gap:12px;align-items:baseline;padding:11px 0;
    border-top:1px solid var(--line);font-size:16px;color:var(--dim)}
  .ent-adds li:last-child{border-bottom:1px solid var(--line)}
  .ent-adds li svg{width:14px;height:14px;flex:none;position:relative;top:2px;color:var(--v1)}
  .ent-adds .btn{margin-top:22px}
  /* One drawing, not a second icon grid: the four-column grid of 104x36 marks
     directly above already owns that treatment, and repeating it here would
     read as the same section twice. Same pen (1.5 stroke, --label base, --v1
     accent, panel-coloured node fills), one size up, with the hero's amber
     glow behind it so the band is not flat text. */
  .ent-art{position:relative;display:flex;justify-content:center}
  .ent-art::before{content:"";position:absolute;inset:-16% -10%;pointer-events:none;
    background:radial-gradient(closest-side,rgba(248,164,52,.13),rgba(248,164,52,0))}
  .ent-art svg{position:relative;width:100%;max-width:300px;height:auto;color:var(--label)}
  .ent-art svg .hi{stroke:var(--v1)}
  .ent-art svg .node{fill:var(--bg)}
  .ent-art svg .faint{opacity:.42}
  .close{text-align:center}
  .close h2{margin:0 auto}
  .close .ctas{display:flex;gap:12px;justify-content:center;margin-top:32px;flex-wrap:wrap}

  @media (max-width:900px){
    .grid{grid-template-columns:1fr 1fr}
    .grid > div:nth-child(3n){border-right:1px solid var(--line)}
    .grid > div:nth-child(2n){border-right:0}
    .grid > div:nth-last-child(-n+3){border-bottom:1px solid var(--line)}
    .grid > div:nth-last-child(-n+2){border-bottom:0}
    .prims{grid-template-columns:1fr 1fr}
    .prims div:nth-child(4n){border-right:1px solid var(--line)}
    .prims div:nth-child(2n){border-right:0}
    .prims div:nth-last-child(-n+4){border-bottom:1px solid var(--line)}
    .prims div:nth-last-child(-n+2){border-bottom:0}
    /* The drawing goes under the list rather than shrinking: below about 300px
       wide the fan-out and the log block stop being readable. */
    .ent-body{grid-template-columns:minmax(0,1fr)}
    .ent-art{justify-content:flex-start}
  }
  @media (max-width:560px){
    .grid{grid-template-columns:1fr}
    .grid > div{border-right:0!important;border-bottom:1px solid var(--line)!important}
    .grid > div:last-child{border-bottom:0!important}
    .prims{grid-template-columns:1fr}
    .prims div{border-right:0!important;border-bottom:1px solid var(--line)!important}
    .prims div:last-child{border-bottom:0!important}
    .ent-who,.ent-body{padding-left:18px;padding-right:18px}
    /* The kicker takes its own line here. Sharing one with the first audience
       and wrapping the other two under it made the strip read as a sentence
       that ran out of room. */
    .ent-who{gap:9px 18px}
    .ent-who .k{flex:0 0 100%}
    .ent-adds .btn{width:100%}
  }
  @media (prefers-reduced-motion:no-preference){
    .hero h1,.hero .lede,.ask-card.home{animation:rise .9s cubic-bezier(.2,.7,.2,1) both}
    .hero .lede{animation-delay:.08s}.ask-card.home{animation-delay:.18s}
    @keyframes rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
  }
