/* Workshop Signal homepage. The page is intentionally editorial: one strong
 * task entry, one recommendation rail, then a small number of useful notes.
 *
 * This file used to declare its own --ws-* palette. Every value in it was a byte-identical
 * copy of a global token, so the namespace has been removed and the rules below name the
 * global tokens directly. That puts the homepage on the same palette as the rest of the
 * storefront and lets the admin design settings reach it. */
.aeri-storefront .aeri-home-native{max-width:100%;overflow:hidden;background:var(--aeri-mineral);color:var(--aeri-black)}
.aeri-storefront .aeri-home-native h1,.aeri-storefront .aeri-home-native h2,.aeri-storefront .aeri-home-native h3{color:var(--aeri-black);font-family:Jost,Arial,sans-serif;text-transform:none;letter-spacing:-.045em}
.aeri-storefront .aeri-home-native a{color:inherit}
.aeri-native-kicker{margin:0 0 14px;color:var(--aeri-clay);font:700 12px/1.2 'Roboto Condensed',Arial,sans-serif;letter-spacing:.16em;text-transform:uppercase}
/* Light-surface kickers read the deepened clay; the support band keeps the base clay because its
 * kicker sits on the black plate (6.6:1 there - darkening it would drop it to 3.7:1). */
.aeri-native-section-head .aeri-native-kicker{color:var(--aeri-clay-text)}
/* The row height is set by the promo tile (its 672/656 ratio, clamped at 435px, exactly as the
 * reference does). The video slot deliberately has no aspect ratio of its own: it stretches to
 * match the tile, which is what object-fill does on the reference's auto-rows-min grid. Forcing
 * 16/9 here made the two slots disagree at widths where the 435px clamp is not yet in play. */
.aeri-native-media-hero{background:var(--aeri-black)}
.aeri-native-hero-inner{max-width:1440px;margin:0 auto;padding:8px var(--aeri-gutter,32px) 0}
.aeri-native-media-hero-grid{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:12px;align-items:stretch}
.aeri-native-media-hero-slot{position:relative;display:block;min-width:0;overflow:hidden;background:var(--aeri-black);color:var(--aeri-white);text-decoration:none}
/* The slot's media is absolutely positioned so it contributes no height of its own. A <video>
 * carries its own intrinsic ratio, and at wide widths that ratio (909px wide -> 511px tall) is
 * taller than the tile's clamped 435px, so the video - not the tile - ended up setting the row
 * height and the two slots disagreed. Taking the media out of flow makes the row purely
 * tile-driven, which is the reference's behaviour, and the media still fills the slot exactly. */
.aeri-native-media-hero-slot img,.aeri-native-media-hero-slot video{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover}
.aeri-native-media-hero-video{min-height:220px}
.aeri-native-media-hero-tile{aspect-ratio:672/656;max-height:435px}
.aeri-native-media-hero-slot:focus-visible{outline:3px solid var(--aeri-lime);outline-offset:-3px}
/* Cut corners. The reference bakes these into its hero video and tile artwork (measured ~44px at
 * 1440: top-left on the video, bottom-right on the tile). AERI's hero media is whatever the admin
 * uploads, so the same silhouette is clipped onto the slots instead. Nothing overflows a slot, so
 * clipping the slot itself is safe here (unlike the search form, whose dropdown is a child). */
.aeri-native-media-hero-grid{--aeri-hero-cut:clamp(20px,3.06vw,44px)}
.aeri-native-media-hero-video{clip-path:polygon(var(--aeri-hero-cut) 0,100% 0,100% 100%,0 100%,0 var(--aeri-hero-cut))}
.aeri-native-media-hero-tile{clip-path:polygon(0 0,100% 0,100% calc(100% - var(--aeri-hero-cut)),calc(100% - var(--aeri-hero-cut)) 100%,0 100%)}
.aeri-native-media-fallback{display:grid;place-items:center;width:100%;height:100%;min-height:200px;padding:30px;background:var(--aeri-muted);color:var(--aeri-signal-lime);font:700 clamp(28px,4vw,60px)/.95 Jost,Arial,sans-serif;text-align:center}
/* Category band — the reference puts its category carousel in its own dark band below the hero,
 * under a centred white headline. AERI's Field Guide tasks are the same idea, so the task picker
 * lives here. Each tile links straight to its task's category archive; there is no selected state
 * and no script behind it. */
/* Proportions measured on the reference at 1440: heading 28/30 sitting 25px under the hero and 32px
 * above the row; 181px items 40px apart; 130px circle with 28px above it and 36px down to a
 * 20/24 regular-weight, normal-case label in the accent colour; 48px under the labels. */
.aeri-native-category-band{background:var(--aeri-black);padding:clamp(18px,1.74vw,25px) 0 clamp(28px,3.4vw,48px)}
/* Scoped to .aeri-storefront .aeri-home-native to outrank the blanket heading rule on line 9
 * (.aeri-storefront .aeri-home-native h2, specificity 0-2-0). A bare .aeri-native-category-heading
 * is 0-1-0 and loses, which rendered this white heading as black on the black band - invisible. */
.aeri-storefront .aeri-home-native .aeri-native-category-heading{margin:0 0 clamp(18px,2.23vw,32px);color:var(--aeri-white);font:700 clamp(20px,1.95vw,28px)/1.07 Jost,Arial,sans-serif;letter-spacing:0;text-align:center;text-transform:uppercase}
.aeri-native-category-strip{display:flex;flex-wrap:wrap;justify-content:center;gap:clamp(14px,2.78vw,40px);max-width:1440px;margin:0 auto;padding:0 var(--aeri-gutter,32px)}
.aeri-native-category-tile{display:flex;flex-direction:column;align-items:center;gap:clamp(12px,2.5vw,36px);padding-top:clamp(6px,1.95vw,28px);color:var(--aeri-white);text-decoration:none}
@media(min-width:1024px){.aeri-native-category-tile{width:clamp(150px,12.6vw,181px)}}
/* Clips at rest - measured at 1440px: the 4px border leaves a 122px padding box, which is the
 * circle that overflow clips against (61px radius), and the 93.2px image square inside it has a
 * 65.9px half-diagonal - its corners are already 4.9px outside the clip and graze the 130px disc's
 * visible rim. Unclipped, a photo whose content reaches its own corners shows those corners as
 * dark blobs under an untouched tile, which is what happened when this rule was removed. The hover
 * rule below lifts the clip, which is where the overshoot is wanted. The transparent border is
 * geometry the measurements rely on, not a colour. */
.aeri-native-category-tile-img{display:grid;place-items:center;width:clamp(84px,9.03vw,130px);height:clamp(84px,9.03vw,130px);padding:clamp(8px,1vw,16px);border:4px solid transparent;border-radius:50%;background:var(--aeri-mineral);overflow:hidden}
.aeri-native-category-tile-img img{width:100%;height:100%;object-fit:contain;transition:transform var(--aeri-motion,280ms) var(--aeri-ease,cubic-bezier(.2,.7,.2,1))}
/* Multiply by the white disc is the identity, so this blend is invisible while the disc clips and
 * exists only for what escapes it: a white-background photo spilling onto the band's black reads
 * as a white rectangle, and the blend dissolves it into the silhouette the measured ring
 * describes. JPEG cannot carry alpha, so the renderer marks those images is-opaque and leaves
 * everything else - PNG, WebP, SVG - unblended, which is what lets a cut-out keep its own colours
 * once it crosses the rim. */
.aeri-native-category-tile-img img.is-opaque{mix-blend-mode:multiply}
.aeri-native-category-tile span{font:400 20px/24px Roboto,Arial,sans-serif;color:var(--aeri-signal-lime);text-align:center}
/* The numbered fallback (no image set) sits on the white circle, so it cannot take the label colour. */
.aeri-native-category-tile-img span{color:var(--aeri-black);font-weight:700}
/* Hover: the product zooms and the clip comes off, so the disc stays put and the product
 * overshoots the rim. No green ring - the label already carries the accent, and a ring around the
 * disc read as a second, competing state on top of it.
 *
 * 1.8 is measured, not felt. A cut-out does not fill its own canvas: the live product reaches
 * 44.1% / 45.5% of the image box from its centre (alpha bbox of the 1024px PNG), so in the 93.2px
 * img box at 1440px it peaks 57.6 / 59.4px from the centre at 1.4x - still 5.6px INSIDE the 65px
 * rim, a zoom with no break in it. 1.6x grazes the rim by 0.8px. 1.8x crosses it by 9.1 / 11.4px,
 * and 2.0x by 17 / 20px, which buries the disc behind the product instead of breaking it. A photo
 * cropped tighter than this one crosses sooner; this is the number that works for the assets the
 * store actually has.
 *
 * What the overshoot renders as depends entirely on the image. A white-background JPEG is blended
 * and maps onto the band's own black, so its product tones land between #000 and #111 (measured
 * across a 1152-point ring: darkest 1, band 17) - the photo's silhouette floating in the black
 * rather than the product. A cut-out PNG is not blended and crosses the rim in its own colours,
 * which is the effect this rule exists for. */
.aeri-native-category-tile:hover .aeri-native-category-tile-img,.aeri-native-category-tile:focus-visible .aeri-native-category-tile-img{overflow:visible}
.aeri-native-category-tile:hover .aeri-native-category-tile-img img,.aeri-native-category-tile:focus-visible .aeri-native-category-tile-img img{transform:scale(1.8)}
.aeri-native-section{max-width:1440px;margin:0 auto;padding:clamp(60px,8vw,120px) var(--aeri-gutter,32px)}
/* The middle band wraps a managed section that is not an editorial card strip - currently the
 * product rail. It adopts the same content box and horizontal padding as .aeri-native-section so
 * it lines up with the bands above and below it, but keeps a tighter vertical rhythm: the rail
 * already carries its own padding, and two full section paddings would double the gap. */
.aeri-native-band{max-width:1440px;margin:0 auto;padding:0 var(--aeri-gutter,32px) clamp(48px,6vw,90px)}
.aeri-native-band .aeri-product-rail{max-width:none}
.aeri-native-section-head{max-width:680px;margin:0 0 36px}
.aeri-native-section-head h2{margin:0 0 12px;font-size:clamp(36px,4.6vw,70px);line-height:.95}
.aeri-native-section-head>p:last-child{max-width:50ch;margin:0;color:var(--aeri-muted);font-size:17px}
.aeri-native-section-head--split{display:flex;justify-content:space-between;align-items:end;gap:30px;max-width:none}
.aeri-native-section-head--split .aeri-native-text-link{margin-bottom:8px;white-space:nowrap}
.aeri-native-text-link{display:inline-flex;align-items:center;gap:10px;color:var(--aeri-black);font:700 14px/1.2 'Roboto Condensed',Arial,sans-serif;letter-spacing:.04em;text-decoration:none;text-transform:uppercase;border-bottom:2px solid var(--aeri-clay);padding-bottom:7px}
.aeri-native-text-link:hover,.aeri-native-text-link:focus-visible{color:var(--aeri-clay)}
/* The band used to sit on #f4f4f4. On request it now matches the page surface, so the grey no
 * longer shows beside the billboard and under the cards. The cards keep their 1px border, which is
 * what defines them against white. */
.aeri-native-recommendations{background:var(--aeri-mineral);max-width:none;padding-right:max(var(--aeri-gutter,32px),calc((100vw - 1440px)/2 + var(--aeri-gutter,32px)));padding-left:max(var(--aeri-gutter,32px),calc((100vw - 1440px)/2 + var(--aeri-gutter,32px)))}
.aeri-native-recommendation-panels{position:relative;min-height:370px}
/* Six across, matching the reference: its Most Popular row is six 216px cards inside the 1376px
 * content box, which is what (1376 - 5*14)/6 works out to. Four columns gave 333px cards that no
 * longer matched the reference density, and left the row half-empty when a job had few products. */
.aeri-native-recommendation-panel{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:14px;align-content:start}
.aeri-native-recommendation-panel[hidden]{display:none}
.aeri-native-product-item{min-width:0}
/* The rail billboard takes the columns the products leave free and stretches to their row height.
 * The panel background is white, so leaving it transparent would show a white block, not a gap. */
.aeri-native-rail-billboard{display:block;position:relative;min-width:0;overflow:hidden;background:#fff;text-decoration:none}
.aeri-native-rail-billboard picture,.aeri-native-rail-billboard img,.aeri-native-rail-billboard video{display:block;width:100%;height:100%;object-fit:cover}
.aeri-native-rail-billboard:focus-visible{outline:3px solid var(--aeri-lime);outline-offset:-3px}
.aeri-native-rail-billboard--full{aspect-ratio:3/1}
.aeri-native-product-item .aeri-product-card{height:100%;border:1px solid #c6c8c2;border-radius:0;background:#fff;box-shadow:none}
.aeri-native-product-item .aeri-product-card-image{height:220px;background:#f4f4f4}
.aeri-native-product-item .aeri-product-card-image img{mix-blend-mode:multiply;object-fit:contain}
.aeri-native-product-item .aeri-product-card-body{padding:16px}
.aeri-native-product-item .aeri-product-card h3{font-size:18px;line-height:1.08}
.aeri-native-product-item .aeri-product-card-feature,.aeri-native-product-item .aeri-product-card-sku,.aeri-native-product-item .aeri-product-rating{font-size:12px}
.aeri-native-product-item .aeri-pick-label{padding:9px 14px;background:var(--aeri-signal-lime);color:var(--aeri-black);font:700 11px/1 'Roboto Condensed',Arial,sans-serif;letter-spacing:.08em;text-transform:uppercase}
.aeri-native-empty{padding:36px;border:1px dashed var(--aeri-line);color:var(--aeri-muted)}
.aeri-native-editorial{background:var(--aeri-mineral)}
.aeri-native-editorial-grid{display:grid;gap:18px}
/* The card has a definite height and the media is a positioning context, so the image cannot size
 * the card. Without this the media had only min-height, `height:100%` on the image resolved to auto,
 * and each card rendered at the image's natural height - 1077px and 1292px at 1440, which made the
 * whole band 3942px tall. Same failure mode as the systems band tiles. */
.aeri-native-editorial-card{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(260px,.75fr);height:clamp(300px,34vw,460px);border-top:1px solid var(--aeri-black);border-bottom:1px solid var(--aeri-black);position:relative}
.aeri-native-editorial-card.is-reverse{grid-template-columns:minmax(260px,.75fr) minmax(0,1.25fr)}
.aeri-native-editorial-card.is-reverse .aeri-native-editorial-card-media{order:2}
/* position:relative makes the media slot the containing block for the picture below. */
.aeri-native-editorial-card-media{position:relative;min-height:0;background:#fff;overflow:hidden}
/* Absolutely positioned so the image cannot contribute height to the card: the card owns the height
 * (clamp above) and the image fills it. `height:100%` here previously resolved to auto because the
 * grid item had no definite height, so the image rendered at its intrinsic size. */
.aeri-native-editorial-card-media picture,.aeri-native-editorial-card-media img,.aeri-native-editorial-card-media video{position:absolute;inset:0;display:block;width:100%;height:100%}
.aeri-native-editorial-card-media img,.aeri-native-editorial-card-media video{object-fit:cover}
.aeri-native-editorial-card-media.is-empty{display:grid;place-items:center;color:var(--aeri-muted);font:700 54px/1 Jost,Arial,sans-serif}
.aeri-native-editorial-card-copy{display:flex;flex-direction:column;justify-content:center;padding:clamp(26px,5vw,70px)}
.aeri-native-index{margin:0 0 20px;color:var(--aeri-clay-text);font:700 13px/1 'Roboto Condensed',Arial,sans-serif;letter-spacing:.12em}
.aeri-native-editorial-card-copy h3{max-width:430px;margin:0 0 15px;font-size:clamp(30px,4vw,58px);line-height:.96}
.aeri-native-editorial-card-copy>p:not(.aeri-native-index){max-width:42ch;margin:0 0 26px;color:var(--aeri-muted);font-size:16px}
/* The CTA link stretches over the whole card, so the media and headline are clickable too. The
 * pseudo-element is positioned against the card (position:relative above), and z-index lifts it
 * above the media slot. A card without a link renders no CTA and stays non-clickable. */
.aeri-native-editorial-card .aeri-native-text-link::after{content:"";position:absolute;inset:0;z-index:1}
.aeri-storefront .aeri-home-native .aeri-native-support{display:flex;align-items:center;justify-content:space-between;gap:30px;padding:clamp(46px,6vw,84px) max(var(--aeri-gutter,32px),calc((100vw - 1440px)/2 + var(--aeri-gutter,32px)));background:var(--aeri-black);color:#fff}
/* Scoped to .aeri-storefront .aeri-home-native to outrank the blanket heading rule on line 9
 * (.aeri-storefront .aeri-home-native h2, specificity 0-2-0). Written bare as
 * .aeri-native-support h2 (0-1-1) it lost, and the 58px heading rendered --aeri-black on a
 * --aeri-black band - present in the DOM, invisible on screen, which read as an empty left half. */
.aeri-storefront .aeri-home-native .aeri-native-support h2{margin:0;color:#fff;font-size:clamp(28px,4vw,58px);line-height:.95}
.aeri-native-support-links{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:12px}
.aeri-native-support-links a{display:inline-flex;align-items:center;gap:10px;padding:14px 17px;border:1px solid rgba(255,255,255,.45);color:#fff;text-decoration:none;font:700 13px/1 'Roboto Condensed',Arial,sans-serif;letter-spacing:.04em;text-transform:uppercase}
.aeri-native-support-links a:hover,.aeri-native-support-links a:focus-visible{border-color:var(--aeri-clay);background:var(--aeri-clay);color:#fff}
@media(max-width:1279px){.aeri-native-recommendation-panel{grid-template-columns:repeat(4,minmax(0,1fr))}}
@media(max-width:1023px){.aeri-native-media-hero-grid{grid-template-columns:minmax(0,1fr);gap:12px}.aeri-native-media-hero-video,.aeri-native-media-hero-tile{max-height:none}.aeri-native-media-hero-video{aspect-ratio:16/9;min-height:0}.aeri-native-category-tile-img{width:96px;height:96px}.aeri-native-category-tile span{font-size:16px;line-height:20px}.aeri-native-recommendation-panel{grid-template-columns:repeat(3,minmax(0,1fr))}
/* Single column: media and copy stack, so the card must size to its content. The fixed height above
 * assumed a side-by-side split where the copy column could scroll within it; stacked, a fixed height
 * would leave the copy a sliver under an absolutely-positioned image. The media takes an aspect
 * ratio instead, which gives it a definite height of its own now that its children are absolute. */
.aeri-native-editorial-card,.aeri-native-editorial-card.is-reverse{grid-template-columns:minmax(0,1fr);height:auto}
.aeri-native-editorial-card.is-reverse .aeri-native-editorial-card-media{order:0}
.aeri-native-editorial-card-media{min-height:0;aspect-ratio:16/9}
.aeri-native-editorial-card-copy{padding:28px 24px 34px}}
@media(max-width:767px){.aeri-native-media-hero-grid{gap:2px}.aeri-native-media-hero-main{min-height:clamp(280px,72vw,420px)}.aeri-native-media-hero-side{grid-template-columns:1fr 1fr;min-height:clamp(140px,38vw,220px);gap:2px}.aeri-native-category-strip{gap:14px 16px;padding:22px var(--aeri-gutter,16px) 26px}.aeri-native-category-tile-img{width:66px;height:66px}.aeri-native-category-tile span{font-size:13px;line-height:16px;max-width:84px}.aeri-native-section{padding:56px var(--aeri-gutter,16px)}.aeri-native-section-head--split{display:block}.aeri-native-section-head--split .aeri-native-text-link{margin-top:18px}.aeri-native-section-head h2{font-size:clamp(38px,11vw,54px)}.aeri-native-recommendation-panel{grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.aeri-native-product-item .aeri-product-card-image{height:150px}.aeri-native-product-item .aeri-product-card-body{padding:11px}.aeri-native-product-item .aeri-product-card h3{font-size:15px}.aeri-native-product-item .aeri-product-card-feature,.aeri-native-product-item .aeri-product-card-sku,.aeri-native-product-item .aeri-product-rating{font-size:10px}.aeri-native-editorial-card-copy{padding:28px 22px 34px}.aeri-native-editorial-card-copy h3{font-size:39px}.aeri-native-support{display:block;padding:46px var(--aeri-gutter,16px)}.aeri-native-support-links{justify-content:flex-start;margin-top:26px}.aeri-native-support-links a{width:100%;justify-content:space-between}}
@media(prefers-reduced-motion:reduce){.aeri-native-editorial-card{transition:none}.aeri-native-editorial-card:hover{transform:none}.aeri-native-social-caption{transition:none}}
