* { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
/* logo cloud marquee: the homepage animates via an ix2 interaction scoped
   to that page only — every other instance was static. One CSS animation
   covers them all (it also overrides the ix2 inline transform, so the
   homepage stays in sync). */
.logo-cloud-hero .desktop-hero, .logo-cloud-hero .mobile-hero { animation: tb-logo-marquee 20s linear infinite alternate; }
@keyframes tb-logo-marquee { from { transform: translateX(0); } to { transform: translateX(-57%); } }
/* sitewide rule: no orphans (single-word last lines); balance headings */
body { text-wrap: pretty; }
h1, h2, h3, h4, h5, h6 { text-wrap: balance; }
/* Type hierarchy: the Webflow export flattened everything to weight 400 —
   base h1-h6 tags are 400, .heading-style-h4 forgot its weight, and the
   label/tag/breadcrumb classes never set one, so the whole page reads at
   a single weight. Restore contrast so headings and labels carry. */
.heading-style-h4 { font-weight: 600; letter-spacing: -.01em; }
.heading-style-h1, .heading-style-h2, .heading-style-h3 { letter-spacing: -.02em; }
.text-style-allcaps { font-weight: 600; letter-spacing: .06em; }
.text-size-tag { font-weight: 500; }
/* breadcrumb: current page reads as the anchor, ancestors recede to grey */
.link-page { font-weight: 500; color: var(--cool-grey--600); }
.tb-detail-crumb > span.link-page:last-child { font-weight: 600; color: var(--black); }
/* form feedback: replace Webflow's grey/red slabs site-wide */
.w-form-done { background: #f0faf4; border: 1px solid #c4e8d1; color: #17663a; border-radius: .5rem; padding: .9rem 1.15rem; font-size: .9rem; line-height: 1.5; text-align: left; }
.w-form-fail { background: #fdf2f2; border: 1px solid #f1cccc; color: #a52a2a; border-radius: .5rem; padding: .9rem 1.15rem; font-size: .9rem; line-height: 1.5; margin-top: .75rem; text-align: left; }
/* auth-dependent UI stays hidden until auth-ui.ts resolves the session */
[tb-hide] { display: none !important; }
/* card hover link/new-tab buttons: match the save (+) button — white bg, no border ring */
.actions-button.share-url, .actions-button.new-page.secondary { background-color: #fff; border: none; }
/* hover-actions gradient overlay covers the image and swallowed clicks on the
   new image→detail links; let clicks fall through except on the buttons */
.component-actions { pointer-events: none; transition: opacity .2s; }
.component-actions .component-actions-buttons { pointer-events: auto; }
/* card hover reveal was a webflow IX2 interaction bound at page load —
   it never binds to React-rendered cards, so do it in CSS. !important
   beats the inline opacity IX2 writes on cards it did bind. */
.cl_collection-item:hover .component-actions { opacity: 1 !important; }
/* image area fills the card frame — the webflow .5rem wrapper padding
   left a band that reads as a misaligned border under the hover overlay */
.cl_ci_image-wrapper { padding: 0; }
.cl_ci_image-sizer { width: 100%; min-height: 0; max-height: 100%; }
/* the detail link wraps the img, so .cl_ci_image{height:100%} resolved
   against the anchor's AUTO height and the thumb rendered at its intrinsic
   height, overflowing the frame. The wrapper is overflow:hidden +
   justify-content:flex-end, so that overflow got cropped off the TOP —
   hero comps lost their headline. Make the anchor fill the frame. */
.cl_ci_image-sizer > a { display: block; width: 100%; height: 100%; min-height: 0; }
/* thumbnails mirror real page placement (data-pos set per card):
   navbar top, footer bottom, everything else centered (webflow default) */
.cl_ci_image-sizer[data-pos="top"] { justify-content: flex-start; }
.cl_ci_image-sizer[data-pos="top"] .cl_ci_image { object-position: top; }
/* tall (portrait) shots fill the frame and show the TOP of the comp.
   Contain shrank a 2880x4300 article into an unreadable pillarboxed
   sliver, and a long-form comp is read from its top anyway. Side padding
   keeps the crop off the card edges. Bottom-anchored comps (footers) keep
   contain, since top-cropping one cuts the part that matters. */
.cl_ci_image-sizer[data-tall] { padding-left: 1.25rem; padding-right: 1.25rem; }
.cl_ci_image-sizer[data-tall] .cl_ci_image { object-fit: contain; }
.cl_ci_image-sizer[data-tall]:not([data-pos="bottom"]) .cl_ci_image { object-fit: cover; object-position: top; }
.cl_ci_image-sizer[data-pos="bottom"] { justify-content: flex-end; }
.cl_ci_image-sizer[data-pos="bottom"] .cl_ci_image { object-position: bottom; }
/* whole-card click → detail. The detail link wraps only the thumbnail,
   so on short cards the click target is a thin band. Stretch the link
   over the whole card and lift the real buttons/title above it. */
.cl_collection-item { position: relative; }
/* open copy dropdown hangs into the next row; the hover-lift transform
   makes sibling cards stacking contexts that would cover it */
.cl_collection-item:has(.dropdown-copy.is-open) { z-index: 5; }
/* stretched ::after on the image link fails: .cl_ci_image-wrapper is
   position:relative + overflow:hidden, so it anchors and clips to the
   thumbnail. Use a real sibling anchor stretched over the card instead. */
.cl_collection-item .card-stretch { position: absolute; inset: 0; z-index: 1; }
.cl_collection-item .component-actions { z-index: 2; } /* stays an absolute hover overlay */
/* button-wrapper above title-wrapper: the copy toggle/dropdown hang into
   the title area, and the later DOM sibling would swallow their clicks */
.cl_collection-item .cl_ci_button-wrapper { position: relative; z-index: 3; }
/* title-wrapper sits above the stretched anchor (dropdown layering), which
   made the whole bottom band swallow whole-card clicks. Pass clicks through
   the wrapper; only its links (the name) stay interactive. */
.cl_collection-item .cl_ci_title-wrapper { position: relative; z-index: 2; pointer-events: none; }
.cl_collection-item .cl_ci_title-wrapper a { pointer-events: auto; }
/* Detail layout (pages AND the ajax overlay — must be global, the overlay
   injects detail content into other pages): image is the hero, compact
   sticky sidebar, similar/examples below. */
.max-width-full.side { display: block; } /* export had flex; detail pages only */
.container-large.tb-detail-full { max-width: none; } /* detail spans the screen; .page-padding keeps the gutters */
/* image is the hero: full-width below a single action bar (title + copy
   buttons). No side column, no side-scroll zoom. */
.tb-detail-grid { display: flex; flex-direction: column; gap: 1.5rem; }
.tb-detail-grid .sidebar { order: -1; position: static; width: 100%; padding: 0 0 1.25rem; border: none; border-bottom: 1px solid var(--divider-light-grey); border-radius: 0; }
/* action bar: title hard-left, all actions (copy buttons + save) clustered
   right. content-wrapper-component is display:contents so title/save flatten
   into siblings we can order alongside the copy buttons. */
.tb-detail-grid .sidebar-content-top { display: flex; flex-flow: row wrap; align-items: center; gap: .75rem; }
.tb-detail-grid .content-wrapper-component { display: contents; }
.tb-detail-grid .text-wrapper-component { order: 1; margin-right: auto; }
.tb-detail-grid .action-wrapper-component { order: 3; }
.tb-detail-grid .heading-style-h4 { font-size: 2rem; line-height: 1.2; }
.tb-detail-grid .component-wrapper { padding-top: 0; }
/* full-width hero: whole shot always visible, no inner scrolling. Height
   capped to the fold, so tall full-page screenshots scale down and center
   with side padding instead of towering; wide shots still fill the width. */
.tb-detail-grid .image-wrapper { width: 100%; height: auto; max-height: none; overflow: visible; justify-content: flex-start; align-items: center; padding: .75rem; border-radius: .5rem; }
.tb-detail-image { width: auto; max-width: 100%; height: auto; max-height: 82vh; background: #fff; border-radius: .25rem; }
/* copy menu in the bar: same card CopyMenu, but the wrapper sits in flex
   flow (webflow positions it absolute for cards) and the dropdown
   overlays below-right instead of pushing the bar taller */
.tb-detail-grid .copy-wrapper { order: 2; position: relative; right: auto; z-index: 10; align-items: stretch; }
/* toggle and save (+) share one geometry: 2.75rem tall, .375rem radius, 1px border */
.tb-detail-grid .copy-toggle { height: 2.75rem; border-radius: .375rem; box-shadow: none; }
.tb-detail-grid .dropdown-copy { position: absolute; top: 100%; bottom: auto; left: auto; right: 0; width: 8.75rem; }
/* invisible hover bridge across the .5rem margin gap between toggle and
   menu — without it, crossing the gap fires mouseleave and closes the menu.
   Must span the full menu width (8.75rem, right-aligned), not just the
   toggle: the menu hangs left of the button and a diagonal move crosses
   the gap there. */
.tb-detail-grid .copy-wrapper:has(.dropdown-copy.is-open)::after { content: ''; position: absolute; top: 100%; left: auto; right: 0; width: max(100%, 8.75rem); height: .5rem; }
.tb-detail-grid .tbd-comp.page { order: 2; }
.tb-detail-tags { margin-top: 1rem; }
/* attribute-derived description under the chips; pretty keeps the last
   line from stranding a single word at narrow widths */
.tb-detail-copy { max-width: 46rem; }
.tb-detail-copy p { text-wrap: pretty; margin: 0; }
.tb-detail-below { display: grid; grid-template-columns: 1fr 1fr; gap: 2.5rem; margin-top: 3.5rem; }
.tb-detail-crumb { margin-top: 1.5rem; margin-bottom: 1.5rem; }
/* linked-component peek: small corner icon on inspiration images; hovering
   fades in a preview of the comp you'd actually be copying */
.tb-detail-grid .component-wrapper { position: relative; }
.tb-comp-peek { position: absolute; right: 1rem; bottom: 1rem; z-index: 2; display: flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; background: #fff; border: 1px solid var(--divider-light-grey); border-radius: .4rem; box-shadow: 0 2px 8px rgba(0,0,0,.08); }
.tb-comp-peek > img.tb-peek-icon { width: 1rem; height: 1rem; }
.tb-comp-peek-preview { position: absolute; right: 0; bottom: calc(100% + .5rem); width: 20rem; max-width: 70vw; padding: .5rem; background: #fff; border: 1px solid var(--divider-light-grey); border-radius: .4rem; box-shadow: 0 8px 24px rgba(0,0,0,.14); opacity: 0; visibility: hidden; transition: opacity .2s ease, visibility 0s linear .2s; pointer-events: none; }
.tb-comp-peek-preview img { width: 100%; height: auto; border-radius: .25rem; display: block; }
.tb-comp-peek:hover .tb-comp-peek-preview { opacity: 1; visibility: visible; transition: opacity .2s ease; }
@media (max-width: 991px) {
  .tb-detail-below { grid-template-columns: 1fr; }
}
/* similar/examples cards under the detail image: compact, not skyscrapers */
/* frame scales with the card instead of a fixed 12rem: a lone card spans
   the section, and a 740x192 letterbox shrank a normal screenshot to a
   silly sliver floating in grey */
.tb-detail-below .cl_ci_image-sizer { height: auto; aspect-ratio: 16 / 10; }
.tb-detail-below .cl_ci_image-wrapper { flex: none; }
.tb-detail-below .cl_collection-item { height: auto; } /* webflow fixes it at 26rem */
/* detail-below grids reuse the shared React Card (bare mode); one card
   per row, spanning the section. .demo caps the wrapper at 23rem — undo. */
.tb-detail-below .cl_collection-list-wrapper.demo { width: 100%; }
.tb-detail-below .cl_collection-list.homepage { grid-template-columns: 1fr; }
/* on a wide screen one card per row leaves each comp stretched across half
   the viewport — two up reads closer to the gallery */
@media (min-width: 1440px) {
  /* auto-fit, not 1fr 1fr: a section with a single card collapses the empty
     track and spans, instead of sitting half-width beside a hole */
  .tb-detail-below .cl_collection-list.homepage { grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); }
}
/* user-chosen grid density (2/3/4). Desktop only — tablet/mobile keep
   their own responsive column counts from the webflow media queries */
@media (min-width: 992px) {
  .cl_collection-list[style*="--tb-cols"] { grid-template-columns: repeat(var(--tb-cols), 1fr); }
}
/* grid-density toggle: segmented buttons next to search */
.tb-grid-toggle { display: flex; gap: .25rem; }
.tb-grid-toggle button { display: flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; padding: 0; border: 1px solid var(--divider-light-grey); border-radius: .375rem; background: #fff; cursor: pointer; color: var(--cool-grey--50); }
.tb-grid-toggle button.is-active { border-color: currentColor; color: #000; }
.tb-grid-toggle svg { width: 1rem; height: 1rem; }
/* detail sidebar: name row aligned, save (+) reads as a button not a stray glyph */
.sidebar .cms-page_comp_wrap { display: flex; align-items: center; gap: .5rem; }
.sidebar .action-wrapper-component .actions-button.save { width: 2.75rem; height: 2.75rem; border: 1px solid var(--cool-grey--50); border-radius: .375rem; }
.sidebar .lock.large { display: inline-block; vertical-align: middle; margin-left: .4rem; width: 1.125rem; height: 1.125rem; opacity: .55; } /* inline in the h1 so a wrapped title trails the lock instead of floating it mid-block */
/* saved state: filled check, not the washed-out modal 'secondary' look */
.actions-button.save.secondary {
  /* no border: padding (1.25rem x2) already fills the 2.5rem border-box,
     so any border grows the box past its siblings */
  border: none;
  background-color: var(--cool-grey--900);
  background-image: url('https://d3e54v103j8qbb.cloudfront.net/static/custom-checkbox-checkmark.589d534424.svg');
  background-position: 50%;
  background-repeat: no-repeat;
  background-size: 1rem 1rem;
  animation: tb-pop .3s ease;
}
/* success feedback pop — save check (above) + link-copy button */
@keyframes tb-pop { 0% { transform: scale(1); } 35% { transform: scale(1.28); } 100% { transform: scale(1); } }
.actions-button.tb-copied { animation: tb-pop .3s ease; }
/* filter checkboxes: webflow.js fights w--redirected-checked on React DOM,
   so the checked visual is driven by our own class */
.fs-checkbox_button-10.tb-checked {
  border-color: var(--cool-grey--900);
  background-color: var(--cool-grey--900);
  background-image: url('https://d3e54v103j8qbb.cloudfront.net/static/custom-checkbox-checkmark.589d534424.svg');
  background-position: 50%;
  background-repeat: no-repeat;
  background-size: contain;
}
/* ── Site-wide micro-interactions ──────────────────────────────
   Pure CSS, gated on reduced-motion. Buttons get a smooth hover +
   press; cards lift. */
@media (prefers-reduced-motion: no-preference) {
  .button, .w-button, button, [role="button"], .actions-button, .cl_ci_button, input[type="submit"] {
    transition: transform .12s ease, box-shadow .2s ease, background-color .2s ease, color .2s ease, opacity .2s ease;
  }
  .button:active, .w-button:active, button:active, [role="button"]:active,
  .actions-button:active, .cl_ci_button:active, input[type="submit"]:active {
    transform: scale(.96);
  }
  .button:hover, .w-button:hover, input[type="submit"]:hover { transform: translateY(-1px); }
  .cl_collection-item { transition: transform .2s ease, box-shadow .2s ease; }
  .cl_collection-item:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,.06); }
}
