/* Hallmark · macrostructure: stat-led · palette: andercore-signal · type: Archivo + Space Mono */
/* ===========================================================================
   logisticswarehousing.com  -  design system
   Base: Andercore "Steel blueprint at midnight" (refero.design)
   Deviations from the source system, deliberate and recorded:
     1. Control borders use --slate-line (#858182, 5.28:1). Body and secondary
        text use --slate, lifted to #b8b4b5 (9.90:1) because the source tone
        blooms at small sizes on a near-black ground.
     2. Reading text carries letter-spacing 0 and 17px body, against the
        source's -0.02em at 16px. Negative tracking belongs on display type;
        at 15 to 17px on carbon it is what made the copy swim.
     3. Signal Red retained at #e32735 rather than the reference red #c8102e.
        Better contrast on carbon (4.46:1 against 3.45:1), and this is its
        own brand.
   Measured contrast (WCAG 2.1, sRGB):
     chalk/carbon 20.31 | slate/carbon 9.90 | signal/carbon 4.46 (large only)
     chalk on signal fill 4.56 | slate-line/carbon 5.28 (control borders)
   =========================================================================== */

:root{
  color-scheme: dark;

  /* surfaces */
  --carbon:#0b0405;      /* primary dark canvas */
  --graphite:#150e0f;    /* elevated cards on dark */
  --chalk:#ffffff;       /* light canvas + primary text on dark */
  --paper-2:#f4f4f5;     /* light-canvas alternate band */

  /* ink */
  --slate:#b8b4b5;       /* secondary text on dark. 9.90:1 on carbon.
                          Andercore ships #858182 (5.28:1) which is AA but reads
                          thin and blooms at 14px on a near-black ground. */
  --slate-line:#858182;  /* the original, kept for BORDERS only where the lighter
                          value would be too loud as a hairline */
  --steel:#382e30;       /* decorative hairline edges on dark ONLY */
  --ink:#0b0405;         /* text on light canvas */
  --ink-2:#4a4547;       /* secondary text on light canvas */
  --rule-light:#e4e2e2;  /* hairlines on light canvas */

  /* action  -  rationed, never decorative */
  --signal:#e32735;
  --signal-press:#c11f2b;

  --radius:4px;          /* every corner. no exceptions, no pills. */
  --maxw:1200px;
  --gap-section:80px;
  --gap-card:32px;
  --gap-el:24px;

  --font:"Archivo","Inter","DM Sans",system-ui,-apple-system,sans-serif;
  --mono:"Space Mono","JetBrains Mono","IBM Plex Mono",ui-monospace,monospace;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%; scroll-behavior:smooth}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

body{
  margin:0;
  background:var(--carbon);
  color:var(--chalk);
  font-family:var(--font);
  font-size:17px;
  font-weight:400;
  line-height:1.6;
  letter-spacing:0;   /* negative tracking stays on headings, never on reading text */
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

h1,h2,h3,h4{margin:0; font-weight:500; letter-spacing:-0.02em; line-height:1.2}
p{margin:0}
a{color:inherit}
img,video{max-width:100%; height:auto; display:block}

/* ---- type scale (Andercore) ---------------------------------------------- */
.t-display{font-size:clamp(2.25rem,5.2vw,3.5rem); line-height:1.10; letter-spacing:-1.12px}
.t-heading{font-size:clamp(1.75rem,3.4vw,2.5rem); line-height:1.2; letter-spacing:-0.8px}
.t-sub{font-size:1.5rem; line-height:1.2; letter-spacing:-0.48px}
.t-body{font-size:1.0625rem; line-height:1.62; letter-spacing:0}
.t-sm{font-size:0.9375rem; line-height:1.6; letter-spacing:0}
.t-cap{font-size:0.875rem; line-height:1.55; letter-spacing:0}

.muted{color:var(--slate)}
.mono{font-family:var(--mono); letter-spacing:normal}

/* ---- layout -------------------------------------------------------------- */
.wrap{max-width:var(--maxw); margin:0 auto; padding:0 24px}
section{padding:var(--gap-section) 0}
@media(max-width:640px){
  :root{--gap-section:56px; --gap-card:24px}
  .wrap{padding:0 18px}
}

/* light-canvas pages / bands */
.canvas-light{background:var(--chalk); color:var(--ink)}
.canvas-light .muted{color:var(--ink-2)}
.canvas-light .card{background:var(--paper-2); border-color:var(--rule-light)}
.canvas-light .badge{border-color:var(--ink-2); color:var(--ink-2)}

/* ---- nav: the one consistently light surface ----------------------------- */
.nav{
  position:sticky; top:0; z-index:80;
  background:var(--chalk); color:var(--ink);
  border-bottom:1px solid var(--rule-light);
}
.nav-in{display:flex; align-items:center; gap:20px; height:72px}
/* 700, not a larger size. The reference wordmark is far heavier than ours was,
   but "LOGISTICS WAREHOUSING" is 21 characters against that mark's 10, so
   width is the binding constraint here and weight is the lever that adds
   presence without eating the bar. Tightened tracking for the same reason. */
.brand{
  display:flex; align-items:center; gap:12px;
  font-weight:700; font-size:1.0625rem; letter-spacing:0.01em;
  text-transform:uppercase; text-decoration:none; white-space:nowrap;
}
/* Was a red rounded square with a mono "L" typed into it. It is now the real
   mark (logo-mark.svg), so the box, the background and the type are all the
   SVG's job. Only the size and the flex behaviour stay here. */
/* 38px in a 72px bar. Measured against the reference site, whose brand block is 82px
   tall in a 69px bar and deliberately bleeds past it; ours was 22px in 61px,
   about a third of the bar, which read as timid beside it.

   38px is above the ~32px where the slats stop being texture and start being
   noise, so this uses the FULL mark. Compared side by side at exactly 38px
   before choosing: the slats give it depth and say warehouse without touching
   the L. The simple variant stays the favicon's job. */
.brand-mark{width:38px; height:38px; flex:none; display:block}
.nav-links{margin-left:auto; display:flex; gap:4px; align-items:center}
.nav-links a{
  font-size:0.875rem; text-decoration:none; color:var(--ink-2);
  padding:8px 12px; border-radius:var(--radius); white-space:nowrap;
}
.nav-links a:hover{color:var(--ink); background:var(--paper-2)}
.nav-links a[aria-current="page"]{color:var(--ink); font-weight:500}
/* Below 900px the four content links used to be display:none with nothing in
   their place, so the primary nav disappeared entirely on every phone and only
   the footer carried them. They now scroll horizontally instead of vanishing. */
@media(max-width:900px){
  .nav-in{gap:10px}
  .nav-links{overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none;
    margin-left:auto; max-width:64vw}
  .nav-links::-webkit-scrollbar{display:none}
  .nav-links a{padding:8px 9px; font-size:0.8125rem}
  /* the brand used to be squeezed to 0.75rem here to make room for five
     scrolling links. The disclosure menu below reclaims that space, so the
     wordmark keeps its size and only the links change. */
}
/* The brand text is now .brand-name. It used to be a bare text node, so the old
   `.brand span:not(.brand-mark)` selector matched nothing and this rule never
   fired: at a 334px viewport the brand took 196px of the bar and left the nav
   78px, with four links (including Get a quote) painted past the edge of a
   scroller whose scrollbar is hidden. Silently unreachable, and no gate caught
   it because the nav is not inside an overflow:hidden box - it scrolls, so
   technically it is reachable. Nobody discovers it.
   [[feedback_a_guard_that_scans_the_wrong_pages]] */
@media(max-width:420px){ .brand .brand-name{display:none} }

/* ---- mobile nav: a real disclosure, not a hidden scroller -----------------
   Five links do not fit a phone bar. The previous answer was a horizontal
   scroller with `scrollbar-width:none`, which is an affordance-free scroll:
   the links exist, nothing suggests they do.

   Progressive by default, same contract as the term switch: the button ships
   [hidden] and JS reveals it. With JS off the button stays gone and the links
   keep their scrolling row, which is the old behaviour rather than a dead
   control. [[reference_form_guards_that_drop_real_leads]]
   -------------------------------------------------------------------------- */
.nav-toggle{
  display:none; margin-left:auto; align-items:center; gap:9px;
  appearance:none; background:transparent; border:1px solid var(--rule-light);
  border-radius:var(--radius); color:var(--ink); cursor:pointer;
  font-family:var(--mono); font-size:0.75rem; text-transform:uppercase;
  letter-spacing:.02em; padding:0 12px; height:40px; min-width:44px;
}
.nav-toggle[hidden]{display:none}
.nav-toggle:focus-visible{outline:2px solid var(--signal); outline-offset:2px}
.nav-toggle-bars{position:relative; width:16px; height:2px; background:currentColor;
  display:block; transition:background .12s linear}
.nav-toggle-bars::before,.nav-toggle-bars::after{content:""; position:absolute;
  left:0; width:16px; height:2px; background:currentColor; transition:transform .16s ease}
.nav-toggle-bars::before{top:-5px}
.nav-toggle-bars::after{top:5px}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars{background:transparent}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before{transform:translateY(5px) rotate(45deg)}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after{transform:translateY(-5px) rotate(-45deg)}
@media(prefers-reduced-motion:reduce){
  .nav-toggle-bars,.nav-toggle-bars::before,.nav-toggle-bars::after{transition:none}
}

@media(max-width:900px){
  /* only once JS has un-hidden it */
  .nav-toggle:not([hidden]){display:inline-flex}
  .nav-toggle:not([hidden]) ~ .nav-links{
    position:absolute; top:100%; left:0; right:0;
    display:none; flex-direction:column; gap:0; max-width:none; margin:0;
    /* the base rule is align-items:center, which in a COLUMN flex centres the
       links horizontally and shrinks each one to its text width, so the
       separator rules render as stubs. stretch is what makes them rows. */
    align-items:stretch;
    overflow:visible; background:var(--chalk);
    border-bottom:1px solid var(--rule-light);
    box-shadow:0 10px 30px rgba(11,4,5,.16);
    padding:6px 24px 14px;
  }
  .nav-toggle[aria-expanded="true"] ~ .nav-links{display:flex}
  .nav-toggle:not([hidden]) ~ .nav-links a{
    padding:13px 0; min-height:44px; display:flex; align-items:center;
    font-size:0.9375rem; border-top:1px solid var(--rule-light);
  }
  .nav-toggle:not([hidden]) ~ .nav-links a:first-child{border-top:0}
  .nav-in{position:relative}
}

/* ---- buttons: red activates, never decorates ----------------------------- */
.btn{
  display:inline-flex; align-items:center; gap:10px;
  font-family:var(--font); font-size:0.875rem; font-weight:500;
  letter-spacing:-0.28px; text-decoration:none; cursor:pointer;
  padding:13px 24px; border-radius:var(--radius); border:1px solid transparent;
  transition:background-color .15s ease, border-color .15s ease;
}
.btn-primary{background:var(--signal); color:#fff; border-color:var(--signal)}
.btn-primary:hover{background:var(--signal-press); border-color:var(--signal-press)}
.btn-ghost{background:var(--graphite); color:var(--chalk); border-color:var(--steel)}
.btn-ghost:hover{border-color:var(--slate)}
.canvas-light .btn-ghost{background:transparent; color:var(--ink); border-color:var(--ink-2)}
.btn:focus-visible{outline:2px solid var(--signal); outline-offset:2px}
.canvas-light .btn-primary:focus-visible{outline-color:var(--ink)}

/* ---- badge / eyebrow: outlined instrument label -------------------------- */
.badge{
  display:inline-block; font-family:var(--mono); font-size:0.8125rem;
  color:var(--slate); border:1px solid var(--slate-line); border-radius:var(--radius);
  padding:7px 12px; letter-spacing:normal;
}
.eyebrow{
  display:block; font-family:var(--mono); font-size:0.8125rem; color:var(--slate);
  text-transform:uppercase; margin-bottom:16px; letter-spacing:normal;
}
.eyebrow::after{
  content:""; display:block; width:28px; height:1px;
  background:var(--signal); margin-top:8px;
}

/* ---- cards: lines, never shadows ----------------------------------------- */
.card{
  background:transparent; border:1px solid var(--steel);
  border-radius:var(--radius); padding:var(--gap-card);
}
.card-raised{background:var(--graphite)}
.grid{display:grid; gap:var(--gap-card)}
/* minmax(0,1fr), never a bare 1fr. A bare 1fr is minmax(auto,1fr) and refuses to
   shrink below its content's min-width, so at 320px the single collapsed column
   stayed 350px wide, the page overflowed, and body's overflow-x:hidden clipped
   the quote form's submit button out of reach. Same trap as the footer grid. */
.grid-3{grid-template-columns:repeat(3,minmax(0,1fr))}
.grid-2{grid-template-columns:repeat(2,minmax(0,1fr))}
@media(max-width:880px){.grid-3,.grid-2{grid-template-columns:minmax(0,1fr)}}

/* ---- spec strip: instrument readout -------------------------------------- */
.specs{border-top:1px solid var(--steel); margin-top:40px}
.spec{
  display:flex; align-items:baseline; gap:16px;
  padding:16px 0; border-bottom:1px solid var(--steel);
}
.spec-k{
  font-family:var(--mono); font-size:0.8125rem; color:var(--slate);
  text-transform:uppercase; letter-spacing:.02em; flex:none; min-width:200px;
}
.spec-v{font-size:1.5rem; font-weight:500; letter-spacing:-0.48px; margin-left:auto}
.spec-n{font-size:0.9375rem; color:var(--slate); flex:1 1 240px; line-height:1.55}
@media(max-width:640px){
  .spec{flex-wrap:wrap; gap:6px}
  .spec-k{min-width:100%}
  .spec-v{margin-left:0; order:2}
  .spec-n{order:3; flex-basis:100%}
}

/* ---- hero: poster is LCP, video arrives later ---------------------------- */
/* 720px, not 640: at a 1280 content width the hero box was 2.00:1 while the
   video is 16:9, so object-fit:cover scaled the footage up ~12% and cropped
   11% off the top and bottom. Earlier plates had sky and road to spare; the
   flag take is tight on the truck and read as zoomed in. 1280/720 is 1.78,
   which matches the source exactly and removes the crop. */
.hero{position:relative; min-height:min(78vh,720px); display:flex; align-items:flex-end}
/* The clip belongs to the MEDIA, not to the hero. It sat on .hero, so at 320px
   the taller stacked copy + buttons were cut off and the second CTA became
   unreachable. The media is absolute inset:0 and object-fit:cover, so clipping
   it there covers everything the hero clip was ever doing. */
.hero-media{position:absolute; inset:0; z-index:0; background:var(--carbon); overflow:hidden}
.hero-media img,.hero-media video{
  width:100%; height:100%; object-fit:cover; object-position:center right;
}
.hero-media video{position:absolute; inset:0; opacity:0; transition:opacity .8s ease}
.hero-media video.on{opacity:1}
/* The overlay was tuned against night footage, where it only had to deepen an
   already-dark plate. Over the daylight tracking shot it was flattening a blue
   sky to near-black. Keep the left third genuinely dark, because the white
   headline sits there over a bright trailer, then fall off much faster so the
   sky, palms and red stripe survive on the right. */
.hero::after{
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    linear-gradient(90deg, var(--carbon) 5%, rgba(11,4,5,.84) 36%, rgba(11,4,5,.34) 58%, rgba(11,4,5,.08) 80%, transparent 92%),
    linear-gradient(0deg, var(--carbon) 1%, transparent 34%);
}
.hero-in{position:relative; z-index:2; width:100%; padding-block:96px 64px}
.hero h1{max-width:16ch}
.hero p{max-width:52ch; margin-top:20px; color:var(--slate)}
.hero-actions{display:flex; flex-wrap:wrap; gap:12px; margin-top:32px}
@media(prefers-reduced-motion:reduce){.hero-media video{display:none}}

/* ---- forms: control borders use slate, not steel ------------------------- */
.field{display:flex; flex-direction:column; gap:8px; margin-bottom:16px}
.field label{font-family:var(--mono); font-size:0.8125rem; color:var(--slate); text-transform:uppercase; letter-spacing:.02em}
.field input,.field select,.field textarea{
  font-family:var(--font); font-size:1rem; color:var(--chalk);
  background:var(--carbon); border:1px solid var(--slate-line);
  border-radius:var(--radius); padding:12px 14px; width:100%;
}
.field textarea{min-height:110px; resize:vertical}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:2px solid var(--signal); outline-offset:1px; border-color:var(--signal);
}
.canvas-light .field input,.canvas-light .field select,.canvas-light .field textarea{
  color:var(--ink); background:var(--chalk); border-color:var(--ink-2);
}
.canvas-light .field label{color:var(--ink-2)}

/* ---- tables: AI-citable spec data ---------------------------------------- */
.tbl-wrap{overflow-x:auto; border:1px solid var(--steel); border-radius:var(--radius)}
.canvas-light .tbl-wrap{border-color:var(--rule-light)}
table{width:100%; border-collapse:collapse; font-size:0.9375rem; min-width:560px}
th{
  text-align:left; font-family:var(--mono); font-size:0.8125rem; font-weight:400;
  color:var(--slate); text-transform:uppercase; padding:14px 16px; letter-spacing:.02em;
  border-bottom:1px solid var(--steel); white-space:nowrap; letter-spacing:normal;
}
td{padding:14px 16px; border-bottom:1px solid var(--steel); color:var(--slate)}
td:first-child{color:var(--chalk)}
tbody tr:last-child td{border-bottom:0}
.canvas-light th{border-bottom-color:var(--rule-light)}
.canvas-light td{border-bottom-color:var(--rule-light); color:var(--ink-2)}
.canvas-light td:first-child{color:var(--ink)}
td.num{text-align:right; font-family:var(--mono); letter-spacing:normal}

/* ---- steps: mono counters, red active ------------------------------------ */
.steps{display:flex; flex-wrap:wrap; gap:32px; border-top:1px solid var(--steel); padding-top:24px}
.step{flex:1 1 200px}
.step-n{font-family:var(--mono); font-size:0.8125rem; color:var(--slate); letter-spacing:.02em}
.step h3{font-size:1rem; margin-top:10px}
.step p{font-size:0.9375rem; color:var(--slate); margin-top:8px; line-height:1.6}

/* ---- footer -------------------------------------------------------------- */
.foot{border-top:1px solid var(--steel); padding:56px 0 40px; font-size:0.9375rem; color:var(--slate); line-height:1.6}
.foot a{color:var(--slate)}
.foot a:hover{color:var(--chalk)}
.foot-grid{display:grid; grid-template-columns:2fr 1fr 1fr; gap:32px}
/* minmax(0,1fr), not 1fr. A bare 1fr is minmax(auto,1fr), so a track refuses to
   shrink below its content's min-width: at 320px the first column claimed 196px
   of a 284px box and pushed the second to 334px, putting the footer's
   "Warehousing services" link past the viewport edge. Found 2026-08-25 only
   after audit-clipped-content stopped testing one hardcoded 390px width.
   Below 420px two columns cannot hold these labels at all, so stack. */
@media(max-width:760px){.foot-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}
@media(max-width:420px){.foot-grid{grid-template-columns:minmax(0,1fr); gap:28px}}
.foot h4,.foot .foot-h{font-family:var(--mono); font-size:0.8125rem; color:var(--slate); text-transform:uppercase; margin-bottom:14px; font-weight:400}
.foot ul{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:10px}
.foot ul a{text-decoration:none}

/* skip link */
.skip{position:absolute; left:-9999px}
.skip:focus{
  left:16px; top:12px; z-index:200; background:var(--signal); color:#fff;
  padding:10px 16px; border-radius:var(--radius); font-size:0.875rem;
}

/* ---- interior page head --------------------------------------------------- */
.page-head{padding-top:72px; padding-bottom:8px}
.page-head h1{max-width:18ch}
.page-head .hero-actions{margin-top:28px}
.page-head + section{padding-top:48px}

/* ---- footer is ALWAYS dark, on every page canvas --------------------------
   Bug caught 2026-08-25: on a .canvas-light page the footer inherited the white
   body background while its brand text kept color:var(--chalk). White on white
   measured 1.0:1 (invisible) and the footer body text measured 3.85:1 (fails AA
   body). Pinning the footer to carbon fixes both and matches the source system's
   dark-dominant rule. Do not let the footer inherit the page canvas again. */
.foot{background:var(--carbon); color:var(--slate); border-top-color:var(--steel)}
.foot .brand{color:var(--chalk)}
.foot a{color:var(--slate)}
.foot a:hover{color:var(--chalk)}
.foot h4,.foot .foot-h{color:var(--slate)}
.canvas-light .foot,
body.canvas-light .foot{background:var(--carbon); color:var(--slate)}
body.canvas-light .foot .brand{color:var(--chalk)}
body.canvas-light .foot a{color:var(--slate)}
body.canvas-light .foot a:hover{color:var(--chalk)}

/* ---- reading measure on long-form light pages -----------------------------
   A 70ch text column inside a 1200px container leaves the right half empty and
   reads as a broken layout. Long-form pages get a tighter container. */
body.canvas-light main .wrap{max-width:900px}
body.canvas-light .page-head h1{max-width:20ch}

/* honeypot: present in the DOM for bots, never shown or focusable for people */
.hp{position:absolute!important; left:-9999px!important; width:1px; height:1px; overflow:hidden}

/* ---- mobile hero + table affordances -------------------------------------
   The hero overlay is a horizontal gradient because the desktop headline sits
   in the left third. On a narrow screen the copy spans the full width, so that
   same gradient darkens the entire frame and the footage disappears. Below
   760px the overlay becomes vertical: image readable at the top, copy on a
   darkened base. */
@media (max-width: 760px){
  .hero{min-height:min(84vh,620px)}
  .hero-media img,.hero-media video{object-position:72% center}
  /* Mobile stacks the copy over the middle of the frame rather than beside it,
     and the daylight plate is a white trailer exactly there. Lifting this to
     match the desktop change measured 2.98:1 on the eyebrow and 2.92:1 on the
     h1, both failing. Keep the top open so the sky reads, then ramp hard from
     just above where the copy starts. */
  .hero::after{
    background:
      linear-gradient(180deg, rgba(11,4,5,.10) 0%, rgba(11,4,5,.45) 24%, rgba(11,4,5,.80) 42%, var(--carbon) 76%);
  }
  .hero-in{padding-block:150px 40px}   /* padding-block only: .wrap owns the gutter */
  .hero h1{max-width:none}
  .hero-actions .btn{flex:1 1 100%; justify-content:center}
}

/* A table wider than its container scrolls, but nothing says so. Fade the
   right edge while it is scrollable so the clipped column is discoverable. */
.tbl-wrap{position:relative; background-attachment:local,local,scroll,scroll;
  background-image:
    linear-gradient(to right, var(--carbon), var(--carbon)),
    linear-gradient(to left,  var(--carbon), var(--carbon)),
    linear-gradient(to right, rgba(0,0,0,.55), rgba(0,0,0,0)),
    linear-gradient(to left,  rgba(0,0,0,.55), rgba(0,0,0,0));
  background-position:0 0, 100% 0, 0 0, 100% 0;
  background-repeat:no-repeat;
  background-size:22px 100%, 22px 100%, 14px 100%, 14px 100%;
}
.canvas-light .tbl-wrap{
  background-image:
    linear-gradient(to right, var(--chalk), var(--chalk)),
    linear-gradient(to left,  var(--chalk), var(--chalk)),
    linear-gradient(to right, rgba(0,0,0,.20), rgba(0,0,0,0)),
    linear-gradient(to left,  rgba(0,0,0,.20), rgba(0,0,0,0));
}

/* footer legal line:
   "(c) YEAR <brand> - South Florida - All rights reserved." */
/* The legal line was 13px slate. Technically 9.9:1, but small type on a
   near-black ground still reads as unreadable, which is what Greg reported.
   Size up and lift the tone; it is one short line, it can afford it. */
.foot-legal{margin-top:36px; padding-top:22px; border-top:1px solid var(--steel);
  color:var(--slate); font-size:0.9375rem; line-height:1.6; letter-spacing:0}

/* ---- asymmetric feature split ---------------------------------------------
   Replaces the three-equal-cards row, which is a named AI tell (taste-skill
   9.C). One lead tile carrying a real photograph, two supporting tiles
   stacked beside it. Collapses to a single column under 880px. */
.feature-split{display:grid; grid-template-columns:1.35fr 1fr; gap:var(--gap-card); margin-top:36px}
.feature-split .stack{display:grid; gap:var(--gap-card); align-content:start}
@media(max-width:880px){.feature-split{grid-template-columns:1fr}}
.tile{border:1px solid var(--steel); border-radius:var(--radius); background:var(--graphite); overflow:hidden}
.tile-media{position:relative; aspect-ratio:3/2; background:var(--carbon)}
.tile-media img{width:100%; height:100%; object-fit:cover; display:block}
.tile-media::after{content:""; position:absolute; inset:0;
  background:linear-gradient(180deg, transparent 45%, rgba(11,4,5,.85) 100%)}
.tile-body{padding:var(--gap-card)}
.tile-body h3{margin-top:14px}

/* ---- interior page hero ---------------------------------------------------
   Every page carries its own photograph. Same overlay logic as the homepage
   hero: horizontal gradient on desktop where the copy sits left, vertical on
   mobile where the copy spans full width and a horizontal ramp would black out
   the whole frame. */
.page-head{position:relative; overflow:hidden; padding:0; min-height:min(56vh,440px);
  display:flex; align-items:flex-end}
.page-head-media{position:absolute; inset:0; z-index:0; background:var(--carbon)}
.page-head-media img{width:100%; height:100%; object-fit:cover; object-position:center}
.page-head::after{content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    linear-gradient(90deg, var(--carbon) 6%, rgba(11,4,5,.86) 46%, rgba(11,4,5,.30) 82%),
    linear-gradient(0deg, var(--carbon) 3%, transparent 52%);}
.page-head-in{position:relative; z-index:2; width:100%; padding-block:104px 52px}
.page-head-in h1{max-width:18ch}
.page-head + section{padding-top:56px}
@media(max-width:760px){
  .page-head{min-height:min(62vh,420px)}
  .page-head-media img{object-position:68% center}
  .page-head::after{background:linear-gradient(180deg, rgba(11,4,5,.22) 0%, rgba(11,4,5,.58) 44%, var(--carbon) 90%)}
  .page-head-in{padding-block:120px 36px}
  .page-head-in h1{max-width:none}
}

/* ---- reading measure on the long-form pages -------------------------------
   These pages are answer-first prose: a heading, a 40-to-60 word direct answer,
   then a table. At the full 1200px container that leaves a 70ch paragraph with
   ~650px of dead space beside it, which reads as a broken column rather than as
   deliberate space. Measured on /contract-vs-public-warehousing/ 2026-08-25.
   The constraint used to hang off .canvas-light and was lost when every page
   moved to the dark theme, so it lives on its own class now. Tables opt back
   out, because they carry more columns than the prose needs. */
body.longform main section .wrap{max-width:900px}
body.longform .page-head .wrap{max-width:var(--maxw)}
body.longform main section .tbl-wrap{width:100%}
body.longform .t-body,
body.longform .answer{max-width:68ch}

/* ---- connector line + nodes ------------------------------------------------
   From the source system: "1px line in #382e30 with small square nodes at
   junction points, occasionally terminating in a red square node." It links
   related items into one system instead of leaving them as loose cards. This
   was in the DESIGN.md component list and did not get built the first time. */
.connector{position:relative; padding-left:26px}
.connector::before{content:""; position:absolute; left:6px; top:6px; bottom:6px;
  width:1px; background:var(--steel)}
.connector .node{position:relative}
.connector .node::before{content:""; position:absolute; left:-24px; top:9px;
  width:7px; height:7px; background:var(--chalk); border-radius:1px}
.connector .node:last-child::before{background:var(--signal)}
.connector .node + .node{margin-top:22px}

/* ---- service area diagram --------------------------------------------------
   Not decoration. Each row is a real destination with its approximate road
   distance, ordered outward from the facility, so the diagram answers "do you
   reach me" without a paragraph. Rendered as a flat dark-on-dark instrument
   diagram with a single red node on the origin, per the source system's
   treatment of diagrams. */
.area{margin-top:40px; border-top:1px solid var(--steel)}
.area-row{display:grid; grid-template-columns:minmax(150px,1fr) 1fr auto; gap:16px;
  align-items:center; padding:15px 0; border-bottom:1px solid var(--steel)}
.area-row .place{font-size:0.9375rem; color:var(--chalk)}
.area-row .bar{position:relative; height:1px; background:var(--steel)}
.area-row .bar span{position:absolute; top:-3px; width:7px; height:7px;
  background:var(--slate); border-radius:1px}
/* red node only. Signal on carbon is 4.46:1, under AA for normal text,
   so the LABEL stays chalk and the node carries the colour. */
.area-row.origin .place{color:var(--chalk); font-weight:500}
.area-row.origin .bar span{background:var(--signal)}
.area-row .dist{font-family:var(--mono); font-size:0.8125rem; color:var(--slate);
  letter-spacing:.02em; white-space:nowrap}
@media(max-width:640px){
  .area-row{grid-template-columns:1fr auto; gap:10px}
  .area-row .bar{display:none}
}

/* ---- form error notice ----------------------------------------------------
   Shown when the handler bounces a submission a real person could plausibly
   have triggered (autofill beating the dwell timer, a whole office sharing one
   NAT address, a password manager filling the honeypot). Hidden by default and
   revealed by the ?e=1 flag, so a bot learns nothing and a human is never left
   staring at a form that silently reappeared. */
.form-note{display:none; border-left:3px solid var(--signal);
  background:color-mix(in srgb, var(--signal) 9%, transparent);
  padding:16px 18px; border-radius:0 var(--radius) var(--radius) 0; margin-bottom:20px}
.form-note p{font-size:0.9375rem; line-height:1.6}
.form-note a{color:var(--chalk); font-weight:500}
body.form-error .form-note{display:block}

/* ---- Andercore parity pass -------------------------------------------------
   Six components read off the reference RECORDING, not its stills. The style
   page's preview is a 21s video of the whole site; a screenshot shows the hero
   only, which is how the first build shipped without any of this.
   [[reference_refero_style_pages_embed_a_video]]
   -------------------------------------------------------------------------- */

/* 1. grid texture. the reference dark bands are not flat - a faint 40px rule
      grid sits under them. two hairline gradients, no image, no request. */
.gridded{position:relative}
.gridded::before{
  content:""; position:absolute; inset:0; z-index:0; pointer-events:none;
  background-image:
    repeating-linear-gradient(90deg,var(--steel) 0 1px,transparent 1px 40px),
    repeating-linear-gradient(180deg,var(--steel) 0 1px,transparent 1px 40px);
  opacity:.28;
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 18%,#000 82%,transparent);
          mask-image:linear-gradient(180deg,transparent,#000 18%,#000 82%,transparent);
}
/* position:relative is LOAD-BEARING, not decoration. z-index does nothing on a
   static element, and a positioned pseudo paints above static in-flow content,
   so without this the texture lands on top of the copy rather than under it. */
.gridded > *{position:relative; z-index:1}

/* 2. red inline word emphasis inside a large statement. NEVER on a surface that
      also carries a red button - signal stays rationed to one voice per screen. */
.sig{color:var(--signal)}

/* 3. photo band. edge to edge, hairline separated, no rounding, no gap.
      the single biggest "yours has no life" fix: the reference runs four
      photographs across at full bleed where we ran none. */
.band{
  display:grid; grid-template-columns:repeat(4,1fr);
  border-block:1px solid var(--steel); background:var(--steel);
  gap:1px; margin-top:44px;
}
.band figure{margin:0; position:relative; aspect-ratio:4/5; background:var(--carbon); overflow:hidden}
.band img{width:100%; height:100%; object-fit:cover}
/* the scrim only has to buy the caption its contrast, so it starts at zero and
   is confined to the bottom third. a full-height wash on frames that are already
   near-black turns the photograph into a hole in the page. */
.band figure::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg,transparent 0 62%,rgba(11,4,5,.78) 100%);
}
.band figcaption{
  position:absolute; z-index:2; left:16px; right:16px; bottom:14px;
  font-family:var(--mono); font-size:0.75rem; letter-spacing:.02em;
  text-transform:uppercase; color:var(--chalk);
}
@media(max-width:900px){ .band{grid-template-columns:repeat(2,1fr)} }
@media(max-width:480px){ .band figure{aspect-ratio:3/2} }

/* 4. four-column hairline strip. vertical rules between, no cards, no boxes. */
.quad{
  display:grid; grid-template-columns:repeat(4,1fr);
  border-top:1px solid var(--steel); margin-top:44px;
}
.quad > div{padding:26px 24px 4px; border-left:1px solid var(--steel)}
.quad > div:first-child{border-left:0; padding-left:0}
.quad h3{font-size:1.0625rem}
.quad p{font-size:0.9375rem; color:var(--slate); margin-top:10px; line-height:1.6}
@media(max-width:900px){
  .quad{grid-template-columns:repeat(2,1fr)}
  .quad > div{padding-left:24px; border-left:1px solid var(--steel)}
  .quad > div:nth-child(odd){border-left:0; padding-left:0}
  /* padding-top is already 26px from the base rule, so only the row rule and the
     gap above it are set here. */
  .quad > div:nth-child(n+3){border-top:1px solid var(--steel); margin-top:22px}
}
@media(max-width:560px){
  .quad{grid-template-columns:1fr}
  .quad > div{border-left:0; padding-left:0}
  /* single column: every div after the first needs the rule, which supersedes
     the two-column nth-child(n+3) case rather than doubling it. */
  .quad > div + div{border-top:1px solid var(--steel); margin-top:22px}
}

/* 5. converging connector. three heads drop a hairline into one red node.
      the .connector rules above this block styled a VERTICAL list that no page
      ever used; this is the horizontal form the reference actually runs. */
.converge{margin-top:44px}
.converge-row{display:grid; grid-template-columns:repeat(3,1fr); gap:24px}
.converge-row > div{border:1px solid var(--steel); border-radius:var(--radius);
  background:var(--graphite); padding:22px 22px 24px}
.converge-row h3{font-size:1rem}
.converge-row p{font-size:0.9375rem; color:var(--slate); margin-top:10px; line-height:1.6}
.converge-row .k{font-family:var(--mono); font-size:0.75rem; color:var(--slate);
  text-transform:uppercase; letter-spacing:.02em; display:block; margin-bottom:10px}
/* the drop lines: three stems into a horizontal spine, then one stem down */
.converge-links{height:76px; position:relative}
.converge-links::before{           /* the spine */
  content:""; position:absolute; left:16.66%; right:16.66%; top:38px; height:1px; background:var(--steel);
}
.converge-links i{                  /* one stem per column, decorative */
  position:absolute; top:0; width:1px; height:38px; background:var(--steel);
}
.converge-links i:nth-child(1){left:16.66%}
.converge-links i:nth-child(2){left:50%}
.converge-links i:nth-child(3){left:83.33%}
.converge-links i:nth-child(4){left:50%; top:38px; height:38px}
.converge-node{
  display:flex; align-items:center; justify-content:center;
  width:44px; height:44px; margin:0 auto; border-radius:var(--radius);
  background:var(--signal); color:#fff; font-family:var(--mono); font-size:1.0625rem;
}
@media(max-width:760px){
  .converge-row{grid-template-columns:1fr; gap:16px}
  .converge-links{height:34px}
  .converge-links::before{display:none}
  .converge-links i{display:none}
  .converge-links i:nth-child(4){display:block; left:50%; top:0; height:34px}
}

/* 6. centered statement. the reference breaks its left-aligned rhythm with one
      centered manifesto block; ours ran left-aligned end to end. */
/* px, NOT ch. a ch cap on a wrapper resolves against the wrapper's 17px body
   font while the child heading renders at clamp(...,3.4vw,2.5rem), which wraps
   the display type one word per line. [[feedback_ch_unit_quote_width_trap]] */
.statement{max-width:640px; margin:0 auto; text-align:center}
.statement p{margin-left:auto; margin-right:auto; max-width:560px}
/* the eyebrow is display:block with a red rule hung off ::after, so centring the
   text is not enough - the rule has to be centred on its own. */
.statement .eyebrow::after{margin-left:auto; margin-right:auto}

/* ---- 7. term switch -------------------------------------------------------
   The reference runs a segmented Buyers/Suppliers control. We have one
   audience, so that exact split would be a fourth restatement of a partition
   the page already makes three times. This carries the same component on the
   question a warehousing buyer actually opens with: how long am I committing
   for, and what changes if it is short.

   Tabs, properly: real <button>s in a tablist, arrow-key navigable, and every
   panel is in the DOM and readable with JS off. Nothing here is decoration.
   -------------------------------------------------------------------------- */
.switch{display:flex; gap:0; margin-top:36px; border:1px solid var(--steel);
  border-radius:var(--radius); overflow:hidden; width:max-content; max-width:100%}
.switch button{
  appearance:none; border:0; border-left:1px solid var(--steel); cursor:pointer;
  background:transparent; color:var(--slate); font-family:var(--mono);
  font-size:0.8125rem; letter-spacing:.02em; text-transform:uppercase;
  padding:12px 20px; white-space:nowrap;
}
.switch button:first-child{border-left:0}
.switch button:hover{color:var(--chalk)}
.switch button[aria-selected="true"]{background:var(--signal); color:#fff}
.switch button:focus-visible{outline:2px solid var(--signal); outline-offset:-2px}
/* Roving tabindex plus automatic activation means the tab that has focus is
   ALWAYS the selected one, and the selected tab's fill is --signal, so a
   --signal ring was red on red: a focus indicator that by construction could
   never be seen (WCAG 2.4.7). White on the red fill is 4.56:1. */
.switch button[aria-selected="true"]:focus-visible{outline-color:#fff}
.canvas-light .switch button[aria-selected="true"]{background:var(--ink); color:var(--chalk)}

.term-panel{margin-top:32px}
.term-panel[hidden]{display:none}
.term-grid{display:grid; grid-template-columns:1.1fr 1fr; gap:var(--gap-card); align-items:start}
@media(max-width:880px){.term-grid{grid-template-columns:1fr}}
.term-grid h3{font-size:1.5rem; letter-spacing:-0.48px}
.term-grid > div > p{color:var(--slate); margin-top:14px; line-height:1.62}
.term-facts{border-top:1px solid var(--steel)}
.term-facts div{display:flex; gap:16px; align-items:baseline;
  padding:14px 0; border-bottom:1px solid var(--steel)}
.term-facts dt, .term-facts .k{font-family:var(--mono); font-size:0.75rem;
  color:var(--slate); text-transform:uppercase; letter-spacing:.02em;
  flex:0 0 132px}
.term-facts .v{font-size:0.9375rem; color:var(--chalk); line-height:1.5}
/* Below 520px the three labels cannot share a row. Measured at a 334px
   viewport the strip gets 284px and needs 335px, so overflow:hidden clipped
   "Over 12 months" and the clipped part could not be tapped: an interactive
   control painted outside its own scroll container.
   [[feedback_a_guard_that_scans_the_wrong_pages]] - the clipped-content gate
   passed this because it was run at 390px, above where the bug starts.

   Stack instead of shrinking. Squeezing type to 0.6875rem to buy a row also
   drove the tap target to 40px, under the 44px floor. Full-width rows fix the
   reach and the target together, and the borders just rotate. */
@media(max-width:520px){
  .switch{width:100%; flex-direction:column}
  .switch button{
    width:100%; padding:14px 16px; font-size:0.75rem;
    min-height:44px; text-align:left;
    border-left:0; border-top:1px solid var(--steel);
  }
  .switch button:first-child{border-top:0}
  .term-facts div{flex-direction:column; gap:6px}
  .term-facts dt, .term-facts .k{flex:none}
}
/* Progressive by DEFAULT, not by a class nothing sets. The markup ships the
   strip with [hidden] and all three panels visible; the script reveals the
   strip and then hides the inactive panels. So JS off leaves a readable
   three-section page and no dead buttons, which is the failure mode a tab
   widget usually ships with. [[reference_form_guards_that_drop_real_leads]] */
.switch[hidden]{display:none}
.term-panel + .term-panel{border-top:1px solid var(--steel); padding-top:28px}
.switch:not([hidden]) ~ .term-panel + .term-panel{border-top:0; padding-top:0}
