/* apiant.ai shared layer: brand tokens and the ONE button.
   Linked from the <head> of every page, before that page's own <style>.
   api/_render.js emits the same link for the catalog pages.

   Why this file exists: the primary CTA was defined five times — in
   index.html, pricing.html, api/_render.js, site.js and (as .btn.light)
   again in index.html — and the five copies had drifted to four different
   corner radii (8 / 11 / 13 / 999), two fills and three heights. Same
   label, same destination, four appearances. Anything that draws a button
   takes it from here; nothing redefines .btn in a page style block. */

:root{
  /* ---- ground ---- */
  --bg:#0a0a0a; --bg-2:#111210;
  --line:rgba(255,255,255,.07); --line-2:rgba(255,255,255,.13);

  /* ---- the text ramp, brightest to quietest ----
     Five roles, not four. index.html and the catalog template had both been
     spelling --dim, for OPPOSITE jobs: eyebrows and fine print on the home
     page (#6a6f6c) against lede and intro copy on the catalog (#c7c4be).
     Picking one value would have made home-page eyebrows near-white or
     catalog ledes near-invisible, so the quiet one gets its own name.
     Contrast on #0a0a0a: ink 18.6, dim 11.4, muted 6.1, label 4.86, faint 3.0.
     AA wants 4.5 for small text, so --faint is for
     furniture and counters only. Body copy stops at --muted. */
  --ink:#f7f8f8;      /* primary text */
  --dim:#c7c4be;      /* secondary body: lede, intro */
  --muted:#8b908d;    /* tertiary: descriptions, captions, fine print */
  --label:#7a7f7c;    /* eyebrows, small caps, numeric keys (was #6a6f6c, 3.9:1; raised to 4.86:1 for WCAG AA, 2026-10-26) */
  --faint:#5f5c56;    /* furniture: separators, counters */

  /* ---- brand ----
     Sampled from APIANT-AI.png and cross-checked against the V4 SVG fills.
     The logo's own letterform grey is #e6e7e8; whether --ink should move to
     it is an open question in knowledge/brand-identity.md. Do not change one
     without the other. */
  --v1:#f8a434; --v2:#facd61; --v3:#d96c27;
  --grad:linear-gradient(160deg,#facd61 0%,#f8a434 47%,#d96c27 100%);
  --on-accent:#2a1503;

  /* ---- type ---- */
  --display:"Bricolage Grotesque",ui-sans-serif,system-ui,sans-serif;
  --mono:"JetBrains Mono",ui-monospace,Menlo,monospace;

  /* ---- the rail ----
     One measure. The menu was 1200/24 while every other surface was 1120/20
     or 1120/24, so the wordmark sat 40px left of every heading under it. */
  --w:1120px; --gut:20px;
}

/* The one rail. Anything full-width on the site uses this. */
.rail{width:min(92vw,var(--w));margin-inline:auto;padding-inline:var(--gut)}

/* ---- the button ----------------------------------------------------- */
/* One shape: the amber pill. Ghost is the only secondary. There is no
   white variant — a white button next to an amber one reads as a second,
   different offer, which is exactly the bug this file closes. */

.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.5em;
  height:48px; padding:0 22px; border-radius:999px;
  font-family:var(--display); font-weight:600; font-size:15px; line-height:1;
  white-space:nowrap; text-decoration:none; cursor:pointer;
  border:1px solid transparent;
  background:var(--grad); color:var(--on-accent);
  box-shadow:0 10px 30px -12px rgba(248,164,52,.55);
  transition:filter .15s, border-color .15s, color .15s, background .15s;
}
.btn:hover{filter:brightness(1.06)}
.btn:focus-visible{outline:2px solid var(--v2); outline-offset:2px}

/* Secondary. Never carries the page's main action. */
.btn.ghost{
  background:transparent; color:var(--ink);
  border-color:var(--line-2); box-shadow:none;
}
.btn.ghost:hover{filter:none; border-color:rgba(255,255,255,.35)}

/* Menu size, same shape. NOT named .sm — site.js already owns that class
   for the sticky header element, and it would flatten the button. */
.btn.compact{height:44px; padding:0 18px; font-size:14px}

/* "Free" as a tag inside the button, not a sentence fragment after it.
   Used by the catalog pages; the label stays what tests and copy rules read. */
.btn .free{
  margin-left:.45em; padding:5px 11px; border-radius:999px;
  font-family:var(--mono); font-size:13px; font-weight:500;
  letter-spacing:.12em; text-transform:uppercase; line-height:1;
  background:rgba(42,21,3,.18); color:var(--on-accent);
  border:1px solid rgba(42,21,3,.22);
}

/* Full-width stacking on phones, for every surface that uses .btn. */
@media (max-width:560px){
  .btn{width:100%}
  .btn.compact{width:auto}
}

/* ---- the menu's Start free ------------------------------------------ */
/* site.js draws it with class="btn compact sm-start"; this only pins the bits
   the flex header needs. The fill, radius and weight come from .btn above,
   which is the whole point: the header button and the hero button are now
   the same button at two sizes. */
.sm-start{flex:none}

/* ---- the app tile ------------------------------------------------------- */
/* Drawn by the catalog template (api/_render.js) on several hundred pages and
   by the home page's app band. One definition. The white background behind
   the <img> is deliberate: most vendor logos assume it. It also means a logo
   with WHITE ink vanishes - Anthropic's does - which is a catalog bug to fix
   at the logo endpoint, not by darkening the tile (that breaks the four
   black-ink logos instead). */
.tile{position:relative;display:inline-block;flex:none;width:64px;height:64px;border-radius:16px;overflow:hidden;
background:hsl(var(--h,30) 28% 15%);border:1px solid hsl(var(--h,30) 40% 32%)}
.tile::before{content:attr(data-l);position:absolute;inset:0;display:grid;place-items:center;font-weight:700;font-size:26px;color:rgba(247,248,248,.92);letter-spacing:-.02em}
.tile img{position:relative;display:block;width:100%;height:100%;object-fit:contain;background:#fff}
.tile.lg{width:96px;height:96px;border-radius:24px}.tile.lg::before{font-size:38px}
.tile.sm{width:44px;height:44px;border-radius:12px}.tile.sm::before{font-size:17px}
.tile.xs{width:22px;height:22px;border-radius:6px;vertical-align:middle}.tile.xs::before{font-size:9px}

/* ---- the ask card and its two doors ------------------------------------ */
/* Drawn by the catalog template (/apps, every app and pair page) and by the
   home page hero. One definition. Left door: the assistant, a plain top-level
   POST to app.apiant.ai/chat/start. Right door: the agent route, recessed and
   cool. The card IS the warm frame, so the assistant door is unframed inside
   it; a bordered card inside a bordered card draws the same box twice. */
.ask-card{border:1px solid color-mix(in oklab,var(--v1) 34%,transparent);background:linear-gradient(180deg,rgba(248,164,52,.07),rgba(248,164,52,.015));border-radius:18px;padding:28px 26px}
.ask-card h2{margin-bottom:8px}
.ask-card p:not(.kicker){color:var(--dim);max-width:44em;font-size:16px;line-height:1.6}
.ask-card .kicker{color:var(--label)}
/* The two doors: the catalog cut of the pair on the front page
   (index.html .door.lead / .door.cli). Scaled down.

   BOTH doors are framed, and that is deliberate (Fred, 2026-09-19: "make sure
   it's one OR the other, equal choices"). The rule this replaces said the
   ask-card IS the warm frame so a bordered child would draw the box twice.
   That holds for ONE framed child beside one unframed one, which is what made
   the assistant door read as the card and the agent door as a box inside it.
   With BOTH framed the parent stops being a frame and becomes a group: two
   equal panels inside a warm border read as a segmented choice, which is the
   point. Measured before: panels 482x349 and 420x349, 12.9% apart in area,
   and the agent panel carried no accent pixel at all.
   Every name carries the ask- prefix. .door, .doors, .dgrid, .lead, .k and
   .fine all belong to index.html's page style block; a bare copy here would
   be a second definition of a shared element in a second file, which is the
   bug /site.css exists to close. Same reasoning as .door-mark vs
   pricing.html's .mark. */
/* Two anchors above the stacked doors, phone and tablet only. At 390 the second
   door starts at 877px on an 844px viewport, so stacking hides it: this names
   both routes above the fold. HYPOTHESIS, and instrumented to be settled -
   hero_pick fires on each anchor, to be read against mcp_address_copy. */
.ask-pick{display:flex;gap:8px;margin-top:22px}
.ask-pick a{flex:1 1 0;min-width:0;display:flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:0 10px;border:1px solid var(--line-2);border-radius:12px;background:rgba(255,255,255,.03);color:var(--ink);font-size:13px;line-height:1.3;text-decoration:none;transition:border-color .15s}
.ask-pick a:hover{border-color:var(--v1)}
.ask-pick .ask-mark{width:18px;height:18px;border-radius:5px}
.ask-pick .ask-mark svg{width:11px;height:11px}
.ask-card.home .ask-door{scroll-margin-top:76px}
.ask-doors{display:grid;grid-template-columns:minmax(0,1fr);gap:18px;margin-top:22px}
.ask-door{display:flex;flex-direction:column;min-width:0;border:1px solid var(--line);border-radius:14px;background:rgba(0,0,0,.42);padding:18px}
.ask-card p.ask-lab{display:flex;align-items:flex-start;gap:9px;line-height:1.5;font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--v1);margin-bottom:12px;max-width:none}
/* The catalog card carries the same head as the homepage door (Fred, 2026-09-19:
consistent on all pages). Direct child only: on the homepage the line sits
inside .ask-door with its own spacing. */
.ask-card > p.ask-lab{margin-top:18px}
.ask-mark{flex:none;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:8px;border:1px solid rgba(248,164,52,.32);background:rgba(248,164,52,.1);color:var(--v1)}
.ask-mark svg{display:block;width:14px;height:14px}
.ask-form{display:flex;flex-direction:column;gap:0}
/* The instruction, as a real label. Rebuilt 2026-09-19: the box used to carry
   it in the placeholder, which is the same grey as the chips' text and vanishes
   the moment anyone types, so it could not carry an instruction. index.html has
   its own .ask-card.home .ask-label at (0,3,0) and still wins over this. */
.ask-card .ask-label{display:block;margin-bottom:9px;font-size:16px;font-weight:600;letter-spacing:-.01em;line-height:1.4;color:var(--ink)}
/* The composer is a WELL, not another chip. Measured 2026-09-19: this box and
   the six .ask-try chips carried identical background and border, so six
   buttons and one input were drawn the same way and nothing said where to type.
   The card's ground is a warm amber wash, so the field goes dark and its edge
   goes up to 24% white, well clear of the chips' 11%. Do not bring the two
   treatments back together.
   16px, not 15: iOS Safari zooms the page on focus below 16px. */
.ask-box{width:100%;min-height:132px;resize:vertical;padding:14px 15px;border-radius:13px;border:1px solid rgba(255,255,255,.24);background:rgba(0,0,0,.55);color:var(--ink);font-family:var(--display);font-size:16px;line-height:1.5;outline:none;transition:border-color .15s,box-shadow .15s}
.ask-box:hover{border-color:rgba(255,255,255,.34)}
.ask-box:focus{border-color:var(--v1);box-shadow:0 0 0 3px rgba(248,164,52,.2)}
.ask-box::placeholder{color:#8b8f8d}
/* Submit sits against the box. It used to sit under six chips, 400px below the
   thing it submits. The fine print rides on the same row so it costs no height. */
/* No 760px cap on the composer half. It dated from when the card held
   nothing but the composer; the card now also holds a full-width address
   well, its fine print and the client list, so a capped input beside an
   uncapped well read as two different columns for no reason (Fred, on
   /apps, 2026-09-19). Everything in the card shares one width now. The
   homepage is unaffected: its doors are ~451px, so the cap never bound. */
.ask-go{display:flex;flex-wrap:wrap;align-items:center;gap:12px 14px;margin-top:14px}
.ask-go-fine{font-size:12.5px;line-height:1.45;color:var(--muted)}
.ask-card p.ask-sub{margin-bottom:4px}
/* Sample asks under the composer (pair pages). Quiet on purpose: the same
recessed field colour as the box, so six of them read as one row of options
under the input, not six more buttons competing with the amber pill. A line is
a sentence, up to about a hundred characters, so the chip wraps to two lines
on a phone; 12px corners, not a 999px pill, because a pill on a wrapped line
looks like a lozenge. Hover borrows the box's focus border.
.ask-card p:not(.kicker) is (0,2,1): p.ask-tries-lab must carry the element to
win, same trap as p.ask-fine and p.ask-nudge. */
.ask-tries{display:flex;flex-direction:column;gap:8px;margin-top:22px}
.ask-card p.ask-tries-lab{display:flex;align-items:center;gap:7px;font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--label);max-width:none;line-height:1.4}
.ask-card p.ask-tries-note{margin-top:-3px;font-size:13px;line-height:1.5;color:var(--muted);max-width:68ch}
.ask-tries-list{display:flex;flex-direction:column;gap:10px}
/* Two columns once the card is wide enough (Fred, 2026-09-18: "maximize this
space"). This rule must stay AFTER the flex declaration above: a media query
adds no specificity, so a later display:flex would win it back. */
/* One solution, four asks (Iris, 2026-09-19, measured at 870, 1080 and 1297):
the solution takes the left column across all four rows, the asks stack on the
right. The two sides level each other at every width: as the columns narrow
the solution gains lines at the same rate the asks do. In admin mode the row
wrapper is the grid child, hence the :has() arm. The first placeholder bar
takes the same cell. */
@media (min-width:860px){
.ask-tries-list{display:grid;grid-auto-flow:row;grid-template-columns:minmax(0,1.06fr) minmax(0,1fr);grid-template-rows:repeat(4,minmax(0,1fr));gap:10px}
.ask-tries-list > .ask-try-feat,.ask-tries-list > .ask-try-row:has(.ask-try-feat),.ask-tries-list > .ask-try-ph[data-slot="feat"],.ask-tries-list:not(:has([data-slot])) > .ask-try-ph:first-child{grid-column:1;grid-row:1 / span 4}
.ask-tries-list > .ask-try,.ask-tries-list > .ask-try-row{width:100%;max-width:none}
}
/* Border at .09, not --line (.07, vanishes on the card's amber wash) and not
--line-2 (.13, reads as a second input). Fill a quarter of the composer well's
darkness so the two stay in one family with the well clearly the deeper one.
Text in --dim, not --muted: --muted is the placeholder grey, and six clickable
lines must not render at the weight of an empty field's hint. */
.ask-try{appearance:none;position:relative;display:block;text-align:left;width:100%;max-width:100%;padding:9px 46px 9px 12px;border-radius:12px;border:1px solid rgba(255,255,255,.09);background:rgba(0,0,0,.22);color:var(--dim);font-family:var(--display);font-size:13.5px;line-height:1.45;cursor:pointer;transition:border-color .15s,color .15s,background .15s}
/* The firing app's tile floats into line one; at 22px it is shorter than two
lines of text, so the chip never grows for it and line two runs full width. */
.ask-try > .tile{float:left;margin:2px 10px 1px 0;shape-outside:inset(0 round 6px)}
.ask-try:hover{color:var(--ink);border-color:color-mix(in oklab,var(--v1) 60%,transparent);background:rgba(248,164,52,.08)}
/* Keyboard users get the same ring as .btn; these were the only focusable
things on the site with outline:none. */
.ask-try:focus-visible{outline:2px solid var(--v2);outline-offset:2px;color:var(--ink);border-color:color-mix(in oklab,var(--v1) 60%,transparent)}
/* The push mark: "this goes up there". Drawn like .ask-mark, grey at rest,
amber on hover and focus, trailing edge, centred on a small chip. The 46px
right gutter costs no height: measured, 82 to 104 character lines wrap to the
same count with or without it. */
.ask-push{position:absolute;top:50%;right:9px;transform:translateY(-50%);width:26px;height:26px;border-radius:8px;border:1px solid var(--line-2);background:rgba(255,255,255,.03);color:var(--muted);display:inline-flex;align-items:center;justify-content:center;transition:color .15s,border-color .15s,background .15s}
.ask-push svg{display:block;width:14px;height:14px}
.ask-try:hover .ask-push,.ask-try:focus-visible .ask-push{color:var(--v1);border-color:rgba(248,164,52,.32);background:rgba(248,164,52,.1)}
/* The featured chip: the composer's own 16px in --ink, so it reads as what
typing into the box looks like; a head row with both apps and a one-word
eyebrow; the sentence capped at 64ch with pretty wrapping; the mark bottom
right. No amber: Build it and the two door marks stay the loudest things. */
.ask-try-feat{display:flex;flex-direction:column;justify-content:flex-start;gap:14px;padding:16px 16px 14px;border-radius:14px;background:rgba(0,0,0,.30);font-size:15px;line-height:1.6;color:var(--dim)}
.ask-feat-head{display:flex;align-items:center;gap:9px}
.ask-feat-head .tile{float:none;margin:0}
.ask-feat-arw{display:inline-flex;color:var(--faint)}
.ask-feat-arw svg{display:block}
.ask-feat-lab{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--label)}
.ask-feat-t{display:block;max-width:64ch;text-wrap:pretty;hyphens:none}
.ask-feat-foot{display:flex;align-items:center;justify-content:flex-end;gap:9px;margin-top:auto}
.ask-feat-use{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--label)}
.ask-try-feat:hover .ask-feat-use,.ask-try-feat:focus-visible .ask-feat-use{color:var(--v1)}
.ask-try-feat .ask-push{position:static;transform:none;width:30px;height:30px}
.ask-try-feat .ask-push svg{width:15px;height:15px}
@media (max-width:639px){.ask-try-feat{font-size:14.5px;line-height:1.5;padding:14px;gap:12px}}
.ask-try-row:has(.ask-try-feat){align-items:flex-start}
.ask-try-row:has(.ask-try-feat) .ask-try-x{align-self:flex-start;padding:9px 10px}
.ask-try:active{transform:translateY(1px)}
/* Placeholders while the examples are written: slots, drawn as the empty
shape of what will fill them (Iris, 2026-09-23). An ask slot is the height of
a two-line chip, which is what a line of a hundred characters wraps to in this
column, so nothing jumps when the text arrives; it carries a ghost tile where
the firing app's tile lands and two ghost lines where the text types. The
featured slot (data-slot="feat") carries a ghost head and four ghost lines.
At rest they are still: nothing is being written until the first human
signal, and a shimmer then would say otherwise. HTML rendered before
data-slot existed falls back to :first-child. */
.ask-tries{--ghost:rgba(255,255,255,.055)}
.ask-try-ph{display:block;width:100%;height:59px;pointer-events:none;color:transparent;overflow:hidden}
/* (0,3,0): pair page B paints every .ask-try at (0,2,0) after this file. */
.ask-tries-list > .ask-try.ask-try-ph{border-color:rgba(255,255,255,.07);
  background:linear-gradient(var(--ghost),var(--ghost)) 44px 16px/calc(100% - 100px) 7px no-repeat,linear-gradient(var(--ghost),var(--ghost)) 12px 36px/52% 7px no-repeat,rgba(0,0,0,.16)}
.ask-try-ph::before{content:"";position:absolute;left:12px;top:11px;width:22px;height:22px;border-radius:6px;background:var(--ghost)}
/* The featured slot: two ghost tiles (the second is the first's box-shadow,
so it keeps the radius), a ghost eyebrow, four ghost lines, a ghost foot. */
.ask-tries-list > .ask-try.ask-try-ph[data-slot="feat"],.ask-tries-list:not(:has([data-slot])) > .ask-try.ask-try-ph:first-child{border-radius:14px;
  background:linear-gradient(var(--ghost),var(--ghost)) 100px 24px/52px 6px no-repeat,
    linear-gradient(var(--ghost),var(--ghost)) 16px 61px/calc(100% - 40px) 7px no-repeat,
    linear-gradient(var(--ghost),var(--ghost)) 16px 85px/calc(100% - 64px) 7px no-repeat,
    linear-gradient(var(--ghost),var(--ghost)) 16px 109px/calc(100% - 48px) 7px no-repeat,
    linear-gradient(var(--ghost),var(--ghost)) 16px 133px/48% 7px no-repeat,
    linear-gradient(var(--ghost),var(--ghost)) right 16px bottom 26px/96px 6px no-repeat,rgba(0,0,0,.2)}
.ask-try-ph[data-slot="feat"]::before{left:16px;top:16px;box-shadow:53px 0 0 var(--ghost)}
/* The first slot stands in for the solution: the measured single-column
heights of a 270-character line on a phone and a tablet; at two columns the
grid stretches it to the four slots beside it. */
.ask-try-ph[data-slot="feat"],.ask-tries-list:not(:has([data-slot])) > .ask-try-ph:first-child{height:300px}
@media (min-width:640px){.ask-try-ph[data-slot="feat"],.ask-tries-list:not(:has([data-slot])) > .ask-try-ph:first-child{height:210px}}
@media (min-width:860px){.ask-try-ph[data-slot="feat"],.ask-tries-list:not(:has([data-slot])) > .ask-try-ph:first-child{height:auto}}
/* The two apps' real tiles, dropped into the featured slot's ghost head the
moment writing starts, at the head's own position, so the card that replaces
the slot keeps them where they were. */
.ask-ph-head{position:absolute;left:16px;top:16px;display:flex;align-items:center;gap:9px;animation:ask-pop .34s cubic-bezier(.2,.8,.3,1.25) both}
.ask-ph-head .tile{margin:0}
.ask-try-ph:has(.ask-ph-head)::before{opacity:0}
@media (max-width:639px){.ask-ph-head{left:14px;top:14px}}
@keyframes ask-pop{from{opacity:0;transform:scale(.7)}to{opacity:1;transform:none}}
/* THINK: one amber light walks the empty slots in reading order, one slot
per .7s and a beat of rest (six beats a pass), and each slot's edge warms as
the light crosses it. --i is the slot's place in the walk, set by the script. */
.ask-try-ph::after{content:"";position:absolute;inset:0;opacity:0;pointer-events:none;background:linear-gradient(100deg,transparent 30%,rgba(248,164,52,.07) 42%,rgba(250,205,97,.15) 50%,rgba(248,164,52,.07) 58%,transparent 70%) 100% 0/300% 100% no-repeat}
.ask-tries[data-stage="think"] .ask-try-ph{animation:ask-lit 4.2s ease-out infinite;animation-delay:calc(var(--i,0) * .7s)}
.ask-tries[data-stage="think"] .ask-try-ph::after{animation:ask-scan 4.2s linear infinite;animation-delay:calc(var(--i,0) * .7s)}
@keyframes ask-scan{0%{opacity:1;background-position:100% 0}16.6%{opacity:1;background-position:0 0}16.7%,100%{opacity:0;background-position:0 0}}
@keyframes ask-lit{0%{border-color:rgba(255,255,255,.07)}9%{border-color:rgba(248,164,52,.34)}32%,100%{border-color:rgba(255,255,255,.07)}}
/* The status line, drawn by the script only when the page has slots: the
mark and one plain sentence, one line always (it ellipsizes, never wraps), so
the block's height is fixed from the moment it shows. */
.ask-tries-status{display:flex;align-items:center;gap:8px;min-width:0;height:20px;font-family:var(--mono);font-size:11.5px;line-height:20px;letter-spacing:.01em;color:var(--muted)}
.ask-status-t{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:opacity .17s ease}
.ask-tries-status.is-swap .ask-status-t{opacity:0}
@media (max-width:560px){.ask-tries-status{font-size:11px;letter-spacing:0}}
.ask-spark{flex:none;display:inline-flex;width:14px;height:14px;color:var(--label);transition:color .4s}
.ask-spark svg{display:block;width:14px;height:14px}
.ask-tries:is([data-stage="think"],[data-stage="write"]) .ask-spark{color:var(--v1);animation:ask-twinkle 1.4s ease-in-out infinite alternate}
.ask-tries[data-stage="done"] .ask-spark{color:var(--v1);animation:ask-spark-done .6s ease-out both}
@keyframes ask-twinkle{from{transform:scale(.62) rotate(0);opacity:.55}to{transform:scale(1) rotate(45deg);opacity:1;filter:drop-shadow(0 0 5px rgba(248,164,52,.55))}}
@keyframes ask-spark-done{0%{transform:scale(1)}40%{transform:scale(1.35);filter:drop-shadow(0 0 7px rgba(250,205,97,.7))}100%{transform:scale(1)}}
/* WRITE: the card being written holds the light, types, then cools as the
next one lights. The tile lands first; the push mark and the featured foot
wait until the sentence is in. */
.ask-try.is-writing{border-color:color-mix(in oklab,var(--v1) 55%,transparent);box-shadow:0 0 0 1px rgba(248,164,52,.1),0 12px 34px -16px rgba(248,164,52,.55);transition:border-color .3s,box-shadow .3s}
.ask-try.is-cooling{transition:border-color .9s ease,box-shadow .9s ease,color .15s,background .15s}
.ask-try.is-new > .tile{animation:ask-pop .3s cubic-bezier(.2,.8,.3,1.25) both}
.ask-try.is-new .ask-push,.ask-try.is-new .ask-feat-foot{transition:opacity .35s ease,color .15s,border-color .15s,background .15s}
.ask-try.is-typing .ask-push,.ask-try.is-typing .ask-feat-foot{opacity:0}
/* DONE: one soft edge light passes over the cards in order, then nothing
moves. backwards fill only, so hover owns the border the moment it ends. */
.ask-tries[data-stage="done"] .ask-try{animation:ask-settle .9s ease-out backwards;animation-delay:calc(var(--i,0) * 70ms)}
@keyframes ask-settle{0%{border-color:rgba(255,255,255,.09)}35%{border-color:rgba(248,164,52,.42)}100%{border-color:rgba(255,255,255,.09)}}
.ask-try.is-new{animation:ask-arrive .45s ease-out both}
/* The caret a line carries while it types itself out (TRIES_SCRIPT, 2026-09-23). */
.tw-caret{display:inline-block;width:2px;height:1.05em;margin:0 -1px;vertical-align:-.18em;background:var(--v1);animation:tw-blink .9s steps(1) infinite}
/* The untyped rest of the line: laid out, not shown, so the chip's height is
final from the first frame. The caret's margins net to zero advance, so the
wrap it reserves is the wrap the finished line has. */
.tw-rest{visibility:hidden}
@keyframes tw-blink{50%{opacity:0}}
@media (prefers-reduced-motion:reduce){.tw-caret{display:none}}
/* The backdoor's controls, drawn by the script only when the admin key is in
the page URL: a Remove beside each chip, a Regenerate under the list. Plain
words, not glyphs: the brand fonts have no × or ✓ (see brand-system.md). */
.ask-try-row{display:flex;align-items:stretch;gap:6px;min-width:0}
.ask-try-row .ask-try{flex:1 1 auto;min-width:0}
.ask-try-x{appearance:none;flex:none;padding:0 10px;border-radius:12px;border:1px dashed var(--line-2);background:transparent;color:var(--muted);font-family:var(--mono);font-size:11px;letter-spacing:.06em;cursor:pointer}
.ask-try-x:hover{color:var(--ink);border-color:var(--v1)}
.ask-tries-admin{display:flex;justify-content:flex-end;gap:8px}
.ask-tries-admin .ask-try-x{padding:8px 12px}
.ask-try-key{height:36px;padding:0 12px;border-radius:12px;border:1px dashed var(--line-2);background:rgba(255,255,255,.03);color:var(--ink);font-family:var(--mono);font-size:12px;outline:none;width:min(100%,260px)}
.ask-try-key:focus{border-color:var(--v1)}
@keyframes ask-arrive{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
/* Reduced motion: the same stages in words and edges, nothing moves. The
status line still changes; lines appear whole (TRIES_SCRIPT). */
@media (prefers-reduced-motion:reduce){.ask-try.is-new,.ask-try.is-new > .tile,.ask-ph-head,.ask-tries[data-stage] .ask-try,.ask-tries[data-stage] .ask-try-ph,.ask-tries[data-stage] .ask-try-ph::after,.ask-tries[data-stage] .ask-spark{animation:none}.ask-try.is-writing,.ask-try.is-cooling,.ask-status-t{transition:none}.ask-try.is-writing{box-shadow:none}}
/* The two-door grid that used to live here is gone (2026-09-19). It placed a
label, box, nudge, a Claude Code panel in column two and a two-column chip block
across a :has(#ask-tries) grid. The catalog composer is one column now: label,
box, submit, chips, then the Claude Code route as a line of prose. index.html
still draws two doors with .ask-doors and those rules are above, unchanged; none
of the deleted ones ever matched the home card, which has no #ask-tries. */
/* The nudge: one caption and one arc pointing back up at the composer. It
exists only where the card has two doors. Below 860 the doors stack, the
composer is the first and largest thing in the card, and there is nothing for
the eye to be pulled away from - so it is hidden, not shrunk. It is a flex
child of .ask-form, so display:none takes its 12px gap with it and the phone
card keeps the height it has today.
Muted, not amber, and on purpose: this door already carries an amber border, an
amber wash, an amber eyebrow, an amber sparkle and a 48px amber pill. The pill
is the one saturated thing in it, and a second amber shape 10px above it takes
from the thing we want pressed.
.ask-card p:not(.kicker) is (0,2,1); p.ask-nudge matches it and wins on order.
Do not drop the element from these selectors - a bare .ask-nudge is (0,1,0) and
silently loses font-size, line-height and max-width. Same trap as p.ask-fine. */
.ask-card p.ask-nudge{display:none}
.ask-arc{flex:none;color:var(--label)}
/* Two parts, drawn differently on purpose. The tail is a stroked curve; the
head is a FILLED triangle, not a stroked V. A two-stroke V has to be aimed by
hand at the curve's end tangent, and the first version was seven degrees out
with barbs of different lengths - at 2.2px on a dark ground that reads as a
tick, not an arrowhead. A filled triangle has one tip, sits flush on the line,
and cannot go lopsided. Its tip is the curve's end tangent continued, and the
tail stops at the triangle's base so no seam shows. */
.ask-arc .ask-arc-line{fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.ask-arc .ask-arc-head{fill:currentColor;stroke:none}
/* .ask-card p:not(.kicker) is (0,2,1); p.ask-fine matches it and
   wins on order. Do not drop the element from that selector. */
/* The agent route. It was a bordered panel of near-equal weight beside the
   composer, which asked the visitor to CHOOSE at the moment they should ACT.
   One line under a rule instead. index.html keeps the two-door hero; that page
   is a different layout and was not part of this change. */
.ask-card p.ask-cli-line{display:flex;align-items:flex-start;gap:10px;margin-top:24px;padding-top:18px;border-top:1px solid var(--line);font-size:13.5px;line-height:1.5;color:var(--muted);max-width:none}
.ask-card p.ask-cli-line a{color:var(--dim);text-decoration:none;border-bottom:1px solid var(--line-2)}
.ask-card p.ask-cli-line a:hover{color:var(--ink);border-color:var(--v1)}
.ask-cli-line .ask-mark{width:22px;height:22px;border-color:var(--line-2);background:rgba(255,255,255,.03);color:var(--dim)}
.ask-cli-line .ask-mark svg{width:12px;height:12px}
/* The MCP route on the catalog, pair and solution pages: the same block as the
   homepage door, but one column under a rule after the composer. The 2026-09-19
   rebuild removed a second door BESIDE the box; this is not that. */
.ask-card .ask-mcp{margin-top:24px;padding-top:20px;border-top:1px solid var(--line)}
/* Same word, same reason: this block is always stacked under the composer,
   so the rule alone reads as 'and then', not 'or instead'. */
.ask-card .ask-mcp::before{content:"or";display:block;margin:-2px 0 18px;text-align:center;font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
.ask-card .ask-mcp > .btn{margin-top:18px}
.ask-card .ask-mcp .ask-more{border-top:0;padding-top:0;margin-top:16px}
.ask-card p.ask-cli-lead{font-size:17px;font-weight:600;letter-spacing:-.01em;line-height:1.4;color:var(--ink);margin:0 0 14px;max-width:none}
.ask-card p.ask-fine{font-size:13px;line-height:1.5;color:var(--muted);margin-top:12px;max-width:none}
/* The one place the site prints the MCP address. A dark well like the composer,
   not a chip: it is something to TAKE, not something to press. It holds the
   ADDRESS, never a client's command: the `claude mcp add` line belongs to one
   client and this door is about any of them. overflow-wrap so a longer address
   can never widen the column. Homepage only. */
.ask-card .ask-addr{display:flex;align-items:center;gap:8px;margin:0;padding:12px 14px;border-radius:11px;border:1px solid rgba(255,255,255,.16);background:rgba(0,0,0,.55)}
.ask-card .ask-addr code{flex:1 1 auto;min-width:0;font-family:var(--mono);font-size:14.5px;line-height:1.5;color:var(--ink);word-break:normal;overflow-wrap:anywhere}
.ask-card .ask-copy{position:relative;flex:none;align-self:center;padding:5px 10px;border-radius:8px;border:1px solid var(--line-2);background:rgba(255,255,255,.04);color:var(--muted);font-family:var(--mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;cursor:pointer;transition:color .15s,border-color .15s,background .15s}
/* The button is 27px tall by design - a chip beside the address, not a pill.
   27px fails the 44px touch floor, so the TARGET is grown without growing the
   chip: a transparent overlay 9px beyond every edge takes the tap. Measured
   2026-09-19 (Iris): 51x27 painted, 69x45 tappable. Do not 'tidy' this away. */
.ask-card .ask-copy::after{content:'';position:absolute;inset:-9px}
.ask-card .ask-copy:hover{color:var(--ink);border-color:var(--v1);background:rgba(248,164,52,.1)}
.ask-card .ask-copy.is-done{color:var(--v2);border-color:rgba(248,164,52,.45)}
.ask-card .btn.is-done{background:none;background-color:rgba(248,164,52,.14);color:var(--v2);border:1px solid rgba(248,164,52,.45);box-shadow:none}
.ask-card .ask-cli p.ask-fine{margin-top:18px}
.ask-more{margin-top:18px;padding-top:18px;border-top:1px solid var(--line)}
/* margin:0, not a negative inset. The summary and the list below it are two
   boxes in the same column and must be the same width; a -12px side margin
   made the row 24px wider than the list under it, which is visible on the
   catalog pages where the block has no panel padding to hide it (Fred,
   2026-09-19). The 12px inner padding matches the rows', so the text of
   both lines up too. */
.ask-more > summary{display:flex;align-items:center;gap:10px;min-height:44px;padding:10px 12px;margin:0;border-radius:10px;cursor:pointer;list-style:none;color:var(--ink);font-size:14px;font-weight:500;transition:background .15s}
.ask-more > summary::-webkit-details-marker{display:none}
.ask-more > summary:hover{background:rgba(255,255,255,.03)}
.ask-more > summary:focus-visible,.ask-client-sum:focus-visible{outline:2px solid color-mix(in oklab,var(--v1) 60%,transparent);outline-offset:-2px}
.ask-more-t{flex:1 1 auto}
.ask-chev{flex:none;width:14px;height:14px;color:var(--muted);transition:transform .15s,color .15s}
.ask-more[open] > summary .ask-chev,.ask-client[open] .ask-client-sum .ask-chev{transform:rotate(180deg);color:var(--v1)}
.ask-clients{margin-top:12px;border:1px solid var(--line);border-radius:12px;background:rgba(255,255,255,.02);overflow:hidden}
.ask-client + .ask-client{border-top:1px solid var(--line)}
.ask-client-sum{display:flex;align-items:center;gap:10px;min-height:44px;padding:10px 12px;cursor:pointer;list-style:none;transition:background .15s}
.ask-client-sum::-webkit-details-marker{display:none}
.ask-client-sum:hover{background:rgba(255,255,255,.03)}
.ask-client-sum:hover .ask-chev{color:var(--ink)}
.ask-client[open] .ask-client-sum{background:rgba(248,164,52,.06)}
/* Each product's own mark, bare rather than in a chip, at its own colour where
   it has one (Fred, 2026-09-19). The 24px box is layout only, so a mark with
   its own fill and a mark on currentColor sit on the same baseline and the
   rows keep their rhythm.
   TRADEMARK, on the record: Anthropic's guidelines require materials to be
   approved beforehand, OpenAI's require permission, and VS Code names this
   exact use as not permitted. Fred asked for these marks after being shown
   that. If a vendor objects, the fix is one edit here: drop the fill and the
   path, the layout does not move. */
.ask-client-ico{flex:none;display:grid;place-items:center;width:24px;height:24px;color:var(--dim)}
.ask-client-ico svg{display:block;width:20px;height:20px}
.ask-client[open] .ask-client-ico,.ask-client-sum:hover .ask-client-ico{color:var(--ink)}
.ask-client-ico.own{color:var(--v1);border-color:rgba(248,164,52,.32);background:rgba(248,164,52,.1)}
.ask-client-n{flex:1 1 auto;min-width:0;font-size:14px;font-weight:500;color:var(--ink);line-height:1.3}
.ask-client-b{padding:0 12px 14px 46px}
.ask-card .ask-client-b p{font-size:13px;line-height:1.5;color:var(--dim);max-width:52ch;margin:0 0 10px}
.ask-cmd{display:flex;align-items:center;gap:8px;margin-bottom:12px;padding:8px 10px;border-radius:9px;border:1px solid rgba(255,255,255,.10);background:rgba(0,0,0,.40)}
.ask-cmd code{flex:1 1 auto;min-width:0;font-family:var(--mono);font-variant-ligatures:none;font-size:12.5px;line-height:1.5;color:var(--ink);overflow-wrap:anywhere}
.ask-doc{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--muted);text-decoration:none;border-bottom:1px solid var(--line-2)}
.ask-doc:hover{color:var(--ink);border-color:var(--v1)}
.ask-doc svg{width:12px;height:12px;flex:none}
/* .ask-card p:not(.kicker) is (0,2,1). A bare .ask-legal is (0,1,0) and loses
   its size and colour to it - the trap CLAUDE.md names. Select the element. */
/* ---- Depth glyphs and the step meter (Iris, 2026-09-19) -------------------
   HERE, not in index.html's style block, on purpose: home.html defines its own
   .prims as a different component, so the launch-day swap would drop these
   silently if they lived on the page.
   The grammar is the automation editor's own, at icon scale: rounded pills,
   r=3 nodes, 1.5 orthogonal wires, stroked chevrons. Fixed 104x36, NEVER
   fluid - a scaled SVG thins a 1.5 stroke to nothing on a near-black ground.
   ONE amber object per drawing, and it is the thing the caption names; the
   rest is --label, which is 3.6:1 on the tile ground and clears the 3:1
   non-text floor. Eight amber diagrams would out-shout the one amber CTA. */
.prims svg{display:block;margin-bottom:14px;color:var(--label)}
.prims svg .hi{stroke:var(--v1)}
.prims svg .hif{fill:var(--v1)}
.prims svg .faint{opacity:.45}
.prims svg .node{fill:var(--bg-2)}
/* The step meter: sequence and completeness, which is what those six numbers
   actually carry. 6px inside a 12px mono line, so it costs no height. */
.grid .k{display:flex;align-items:center;gap:10px}
.grid .k svg{flex:none}
.grid .k svg rect{fill:var(--label)}
.grid .k svg rect.on{fill:var(--v1)}
.ask-card p.ask-legal{margin-top:14px;font-size:11.5px;line-height:1.5;color:var(--muted);max-width:none}
@media (prefers-reduced-motion:reduce){.ask-chev,.ask-client-sum,.ask-more > summary{transition:none}}
.ask-doors .btn{align-self:stretch;margin-top:18px}
.ask-alt{display:flex;flex-wrap:wrap;gap:10px}
.ask-alt .btn{align-self:auto}
/* One new breakpoint. The file's only other is max-width:640, a phone rule;
   this is where the card is wide enough for two real columns. */
/* The word, not just a gap. Stacked, the two doors are a screen apart and
   nothing says they are alternatives rather than steps (Fred, on a phone,
   2026-09-20). Side by side the two framed panels carry that themselves, so
   this stops at 860, where the columns start. --muted, never --label, which
   is 3.86:1 on this ground. */
@media (max-width:859px){
.ask-door + .ask-door::before{content:"or";display:block;margin:0 0 16px;text-align:center;font-family:var(--mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
}
@media (min-width:860px){
.ask-pick{display:none}
.ask-doors{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:24px;align-items:start}
/* Equal columns cost the composer 31px, and in the 860-1000 band that was
   enough to push the placeholder past the box: measured 2026-09-19, it wraps
   to 7 lines at 860 and needs 196px against a 132px floor, so Chrome drew a
   scrollbar. The floor now tracks the width instead of being one number:
   210px where the columns are narrowest, easing to 150 once there is room.
   Checked at 860/960/1024/1200/1440 against the longest placeholder the
   templates write. Re-measure if that placeholder grows. */
.ask-box{min-height:clamp(150px,400px - 22vw,210px)}
/* A stretched pill under a 534px textarea reads as a banner, not a button.
   Both doors go to natural width together so the secondary never looks
   larger than the primary. */
.ask-doors .btn{align-self:flex-start;width:auto;min-width:190px}
/* The nudge appears only here, where the card is two columns and the eye can
land on the Claude Code door first. margin-top:-8px pulls the arrowhead to
about 10px under the composer instead of 20px, and takes 8px off the height
the row adds. margin-right on the arc keeps the head about 40px inside the
composer's right edge, clear of the native resize grip that sits in that
corner on desktop. */
.ask-card p.ask-nudge{display:flex;align-items:center;gap:14px;margin-top:2px;
margin-bottom:0;font-family:var(--display);font-size:15.5px;line-height:1.4;font-weight:600;
letter-spacing:-.005em;color:var(--ink);max-width:none}
.ask-card p.ask-nudge span{text-wrap:pretty}
/* The offer is the part worth seeing, so it carries the accent. --v2 rather
than --v1: the lighter end of the ramp on two words reads as emphasis, where
the button's --v1 gradient reads as the action. Measured at every desktop
width down to 860: two lines, never three. */
.ask-card p.ask-nudge b{font-weight:600;color:var(--v2)}
.ask-arc{margin-right:34px}
}

/* ---- Google reviews ------------------------------------------------------ */
/* Drawn by the home page and by the catalog template (/connections, /connect).
The section ships hidden and its page script reveals it only once the widget
has actually drawn something: a third-party embed can be over its quota,
switched off, or blocked by the visitor, and an empty "What our customers say"
heading is worse than no section at all. */
/* The widget's own palette is a light theme: white surfaces, near-black text,
Google blue links. On a near-black page that reads as a pasted-in slab, and
the colours are not reachable from our side of the embed - they are settings
in the Elfsight account. So we retint it here.

It renders into the page's own DOM (no iframe, no shadow root), and alongside
its hashed styled-components classes it carries stable `es-` names, which is
what these rules hook. `!important` is deliberate: the widget ships inline
styles on some of these nodes. If Elfsight rename their `es-` classes in a
future release the rules stop matching and the widget returns to its own light
theme - it does not break, it just looks wrong again, which is the failure
mode to want here. Verified against app release v3.49.14, 2026-09-17.

Only surfaces and text change. The Google wordmark, the verified badges and
the star colour are left alone: they are Google's marks, not ours to retint. */
.revs .es-header-container,
.revs .es-review-background-container{background:rgba(255,255,255,.035)!important;border:1px solid var(--line-2)!important;box-shadow:none!important}
.revs .es-review-background-container{border-radius:16px!important}
.revs .es-header-container{border-radius:14px!important}
.revs [class*="es-header-"],
.revs [class*="es-rating"],
.revs [class*="es-review-author-name"],
.revs [class*="es-review-text"],
.revs [class*="es-review-content"]{color:var(--ink)!important}
.revs [class*="es-review-info"],
.revs [class*="es-review-date"]{color:var(--muted)!important}
.revs .es-text-shortener-control{color:var(--v1)!important}
.revs .es-carousel-arrow-control{background:rgba(255,255,255,.07)!important;color:var(--ink)!important;border:1px solid var(--line-2)!important}
.revs [class*="es-skeleton"]{background:rgba(255,255,255,.06)!important}

/* Collapsed, not display:none. The section has to keep a box so the observer
that loads the widget can see it approach the viewport; display:none has no
box and would never fire. Until the widget draws, the section is nothing: no
heading, no padding, no rule. */
.revs:not(.is-live){padding:0;border:0}
.revs:not(.is-live) .revs-head{display:none}
.revs .revs-head{margin-bottom:18px}

/* Phone. Three nested boxes each kept their desktop padding - the page rail,
the card, then the agent door - so on a 391px screen the composer was left
279px and the placeholder wrapped to four lines inside a box sized for two.
The last line was cut in half and Chrome drew its own light scrollbar and
resize grip on top of the dark card. Trimming the two inner paddings is half
the fix; the floor is the other half. resize:none is phone-only: the grip is
a light native widget on a dark card, and there is no pointer to drag it with.

300px, measured 2026-09-19, not guessed. The longest placeholder any template
writes is the home and app one; with 123px of chrome outside the box and its
own 28px of padding, it wraps to 6 lines at 390 and 8 lines at 320, so the box
must clear 172px and 220px respectively just to stop scrolling. 300 clears the
320px screen by three lines and is about twice the placeholder's own height at
the widths people actually hold, which is the point: a box sized exactly to its
placeholder reads as full before anyone types (Fred, 2026-09-19). Raise the
floor if a longer placeholder is ever written - re-measure, do not estimate. */
@media (max-width:560px){
.ask-card{padding:20px 16px;border-radius:16px}
.ask-door{border:0;border-radius:0;background:none;padding:0}
/* The word, not just a rule. Stacked, the two doors are a screen apart and
   nothing says they are alternatives rather than steps (Fred, on a phone,
   2026-09-20). Side by side the two framed panels carry that on their own, so
   this is the phone and tablet case only. --muted, not --label: --label is
   3.86:1 on this ground. */
.ask-door + .ask-door{border-top:1px solid var(--line);padding-top:20px}
.ask-client-b{padding:0 0 14px 0}
.ask-box{min-height:300px;resize:none}
}

/* ---- Home: the "What would you ask for?" series band (all three home versions) ---- */
.series-band{max-width:1080px;margin:56px auto;padding:0 24px}
.series-band-in{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);align-items:center;gap:0;border:1px solid var(--line-2);border-radius:20px;overflow:hidden;background:var(--bg-2);color:var(--ink);text-decoration:none;transition:border-color .2s,transform .2s,box-shadow .2s}
.series-band-in:hover,.series-band-in:focus-visible{border-color:rgba(248,164,52,.5);transform:translateY(-2px);box-shadow:0 30px 70px -36px rgba(248,164,52,.5)}
.series-band-in:focus-visible{outline:2px solid var(--v2);outline-offset:3px}
.series-band-media{position:relative;display:block;aspect-ratio:16/9;background:#000}
.series-band-media img{display:block;width:100%;height:100%;object-fit:cover}
.series-band-play{position:absolute;left:16px;bottom:16px;display:grid;place-items:center;width:52px;height:52px;border-radius:50%;background:rgba(10,10,10,.55);border:1px solid rgba(250,205,97,.55);color:var(--v2);backdrop-filter:blur(6px)}
.series-band-play svg{width:18px;height:18px;margin-left:3px}
.series-band-text{display:flex;flex-direction:column;gap:12px;padding:30px 34px}
.series-band-k{font-family:var(--mono);font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--v1)}
.series-band-h{font-size:clamp(26px,3vw,36px);font-weight:700;line-height:1.1;letter-spacing:-.02em}
.series-band-p{color:var(--muted);font-size:16px;line-height:1.5;max-width:42ch}
.series-band-go{display:inline-flex;align-items:center;gap:8px;margin-top:4px;font-weight:600;font-size:15px;color:var(--v1)}
.series-band-go svg{width:16px;height:16px;transition:transform .2s}
.series-band-in:hover .series-band-go svg{transform:translateX(3px)}
@media (max-width:760px){.series-band{margin:40px auto;padding:0 16px}.series-band-in{grid-template-columns:1fr}.series-band-text{padding:22px 22px 24px}}
@media (prefers-reduced-motion:reduce){.series-band-in,.series-band-go svg{transition:none}.series-band-in:hover{transform:none}}

/* ---- Home: the "Just ask" film (all three home versions) ----
   The block opens the full-screen player in /film.js; so does the chip that
   sits in the hero's top padding on A and B (absolute, so the H1 and the
   composer do not move). Hidden by /film.js until WISTIA_MEDIA_ID is set. */
.film-block{max-width:1120px;margin:8px auto 0;padding:0 24px}
.film-in{position:relative;display:block;border:1px solid var(--line-2);border-radius:22px;overflow:hidden;background:#000;color:var(--ink);text-decoration:none;transition:border-color .2s,transform .2s,box-shadow .2s}
.film-in:hover,.film-in:focus-visible{border-color:rgba(248,164,52,.55);transform:translateY(-2px);box-shadow:0 40px 90px -40px rgba(248,164,52,.55)}
.film-in:focus-visible{outline:2px solid var(--v2);outline-offset:3px}
.film-media{position:relative;display:block;aspect-ratio:16/9}
.film-media img{display:block;width:100%;height:100%;object-fit:cover}
.film-media::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(10,10,10,0) 55%,rgba(10,10,10,.85) 100%)}
.film-play{position:absolute;left:50%;top:52%;z-index:1;translate:-50% -50%;display:grid;place-items:center;width:clamp(68px,8vw,96px);height:clamp(68px,8vw,96px);border-radius:50%;background:rgba(10,10,10,.55);border:1.5px solid rgba(250,205,97,.75);color:var(--v2);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);transition:background .2s,scale .2s}
.film-play svg{width:34%;height:34%;margin-left:6%}
.film-in:hover .film-play,.film-in:focus-visible .film-play{background:rgba(248,164,52,.22);scale:1.06}
.film-cap{position:absolute;left:0;right:0;bottom:0;z-index:1;display:flex;align-items:flex-end;justify-content:space-between;gap:16px;padding:clamp(16px,3vw,32px) clamp(18px,3.4vw,36px)}
.film-cap-t{display:flex;flex-direction:column;gap:8px;text-align:left}
.film-k{font-family:var(--mono);font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:var(--v1)}
.film-h{font-size:clamp(22px,3.2vw,40px);font-weight:700;line-height:1.05;letter-spacing:-.02em}
.film-len{flex:none;font-family:var(--mono);font-size:13px;letter-spacing:.08em;color:var(--dim);border:1px solid var(--line-2);border-radius:999px;padding:6px 12px;background:rgba(10,10,10,.5)}
/* The chip: an eyebrow above the H1, in the space the hero's top padding already leaves. */
.film-chip{position:absolute;left:50%;translate:-50% 0;z-index:2;display:inline-flex;align-items:center;gap:9px;height:32px;padding:0 14px 0 6px;border-radius:999px;border:1px solid rgba(250,205,97,.45);background:rgba(10,10,10,.6);color:var(--ink);font-family:var(--display);font-size:14px;font-weight:600;line-height:1;text-decoration:none;white-space:nowrap;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.film-chip:hover,.film-chip:focus-visible{border-color:var(--v1)}
.film-chip:focus-visible{outline:2px solid var(--v2);outline-offset:2px}
.film-chip-ico{display:grid;place-items:center;width:22px;height:22px;border-radius:50%;background:var(--grad);color:var(--on-accent)}
.film-chip-ico svg{width:9px;height:9px;margin-left:1px}
.film-chip-len{font-family:var(--mono);font-size:12px;font-weight:400;color:var(--muted)}
.hero > .film-chip{top:calc((clamp(44px,6vh,76px) - 32px) / 2)}
@media (max-width:760px){.film-play{top:40%}.film-block{padding:0 16px}.film-in{border-radius:16px}.film-cap{padding:14px 16px}.film-len{font-size:12px;padding:4px 10px}}
@media (prefers-reduced-motion:reduce){.film-in,.film-play{transition:none}.film-in:hover{transform:none}.film-in:hover .film-play{scale:1}}

/* Long compound words (German "Integrationsingenieur") break with a hyphen
   instead of running off a phone screen. Only where the page language has
   hyphenation rules; English keeps whole words. */
html:not([lang="en"]) h1,html:not([lang="en"]) h2,html:not([lang="en"]) h3{-webkit-hyphens:auto;hyphens:auto;overflow-wrap:break-word}
