/* ============================================================================
   P2 — tinnox.com.au clone. The whole design system, one file.

   This stylesheet belongs to this prototype and nothing else. It deliberately
   does not load /style.css or reach into another prototype's CSS: the point of
   the sites/ folder is that two directions can look nothing alike. Other pages
   of THIS clone will share this file, which is why it is split out of the
   markup rather than inlined the way p1-openai does it.

   The look borrows from two places, and the split between them is deliberate.

   apple.com gives the page its shape: full-bleed product tiles with a white
   line between them, copy at the top of each, a semibold headline rather than
   a poster-weight one, a peek carousel, and a foot of page set almost entirely
   at 12px.

   openai.com/supply/co-lab/work-louder gives it its temperature: white paper,
   near-black ink, wide vertical rhythm, and rounded media. TINNOX's navy
   survives in exactly one place — the button that asks for the sale — because
   spending an accent everywhere is how it stops meaning anything.
   ========================================================================= */

/* ------------------------------------------------------------- tokens -- */
:root {
  --paper:  #ffffff;
  --mist:   #f4f5f7;
  --ink:    #0a0a0b;
  --ink-2:  #3a3d43;
  --muted:  #737880;
  --line:   #e6e8ec;
  --line-2: #d3d7de;
  --night:  #0b0d11;

  /* TINNOX brand navy, lifted from the live site's button. */
  --navy:   #0a456e;
  --navy-2: #0d5789;

  /* SF Pro on the Macs this gets reviewed on is the nearest widely available
     match to OpenAI Sans — same neo-grotesque skeleton, same tolerance for
     very tight tracking at display sizes. Nothing is fetched. */
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
          "Segoe UI Variable Display", "Segoe UI", Inter, Roboto,
          "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --shell: 1240px;
  --stage: 2560px;                    /* apple.com module cap: tiles full-bleed
                                         below this, centered posters above it */
  --gut:   clamp(20px, 4vw, 56px);
  --nav-h: 64px;
  --band:  clamp(64px, 9vw, 132px);   /* vertical air around a band */
  --gap:   12px;                      /* the white line between tiles */

  --ease: cubic-bezier(.2, .7, .2, 1);
}

/* --------------------------------------------------------------- base -- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchors and skip-links must clear the sticky nav. */
  scroll-padding-top: var(--nav-h);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.55;
  letter-spacing: -.011em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, video, iframe { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; margin: 0; padding: 0; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 3px;
  border-radius: 2px;
}

.shell { max-width: var(--shell); margin: 0 auto; padding: 0 var(--gut); }

.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.skip {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  background: var(--ink); color: var(--paper);
  padding: 10px 16px; border-radius: 999px; font-size: 14px;
  transition: top .18s var(--ease);
}
.skip:focus { top: 12px; }

/* --------------------------------------------------------------- type -- */
/* Apple's headline, not OpenAI's. Semibold rather than bold, tracking eased off
   to about -0.02em, and sized to be read rather than to fill the viewport —
   a 116px display headline over a photograph is a poster; this is a product
   page. The mono eyebrows are gone with it. */
.display {
  font-size: clamp(34px, 5vw, 72px);
  font-weight: 600; letter-spacing: -.022em; line-height: 1.06;
  margin: 0; text-wrap: balance;
}
.display-sm { font-size: clamp(30px, 3.4vw, 50px); }

.statement {
  font-size: clamp(26px, 3.7vw, 46px);
  font-weight: 500; letter-spacing: -.028em; line-height: 1.1;
  margin: 0; text-wrap: balance;
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------ buttons -- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  /* 44px is the floor for a thumb; every button clears it at every width. */
  min-height: 44px; padding: 0 22px;
  border: 1px solid var(--line-2); border-radius: 999px;
  font-size: 15px; font-weight: 500; letter-spacing: -.01em;
  /* Transparent, not white: the secondary button sits on the tiles' grey
     ground as often as it sits on paper, and a white fill would show as a
     patch on it. */
  color: var(--ink); background: transparent;
  white-space: nowrap;
  transition: background .2s var(--ease), border-color .2s var(--ease),
              color .2s var(--ease);
}
.btn:hover { border-color: var(--ink); }

.btn-solid {
  background: var(--navy); border-color: var(--navy); color: #fff;
}
.btn-solid:hover { background: var(--navy-2); border-color: var(--navy-2); }
a.btn-solid[href="/get-a-quote/"]:hover {
  background: #fff; color: var(--navy); border-color: var(--navy);
}

.btn-lg { min-height: 52px; padding: 0 30px; font-size: 16px; }

/* Over a photograph the hairline-on-paper secondary disappears, so it inverts.
   The navy primary stays navy — it is the one piece of brand on the page and
   swapping it per background would spend that twice — but picks up a hairline
   so its shape still reads against a dark scrim. */
.btn-on-image {
  color: #fff; border-color: rgba(255, 255, 255, .55);
  background: rgb(8 10 14 / .38);
  backdrop-filter: blur(8px) saturate(1.1);
  -webkit-backdrop-filter: blur(8px) saturate(1.1);
}
.btn-on-image:hover { border-color: #fff; background: rgb(8 10 14 / .55); }
.tile-photo .btn-solid, .tile-gradient .btn-solid {
  border-color: rgba(255, 255, 255, .35);
}

/* ---------------------------------------------------------------- nav -- */
.nav {
  --fly-h: 0px;
  position: sticky; top: 0; z-index: 80;
  overflow: visible;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(1.7) blur(14px);
  -webkit-backdrop-filter: saturate(1.7) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .25s var(--ease);
}
.nav.is-stuck { border-bottom-color: var(--line); }

.nav-in {
  position: relative; z-index: 2;
  max-width: var(--shell); margin: 0 auto;
  padding: 0 var(--gut); height: var(--nav-h);
  display: flex; align-items: center; gap: 30px;
}

/* The mark is a link home, so it needs a thumb-sized box, not just its own
   27px of artwork. */
.brand { flex: none; display: flex; align-items: center; min-height: 44px; }
.mark { display: block; width: 104px; color: var(--ink); }
.mark svg { width: 100%; height: auto; display: block; }

.nav-links {
  display: flex; align-items: center; gap: 28px;
  margin-left: auto; font-size: 14.5px; color: var(--ink-2);
}

/* Product words and Industries share one trigger style. The underline grows
   from the left — the same small tell the OpenAI page uses — and stays put
   while that item's flyout is open, so the bar still points at the section. */
.nav-item { display: flex; align-items: center; }
.nav-item > a,
.nav-item > .nav-trigger {
  position: relative; padding: 6px 0;
  font: inherit; color: inherit; letter-spacing: inherit;
  white-space: nowrap;
}
.nav-item > a::after,
.nav-item > .nav-trigger::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: 0;
  height: 1px; background: var(--ink);
  transition: right .28s var(--ease);
}
.nav-item > a:hover::after,
.nav-item > a[aria-current]::after,
.nav-item[data-open] > a::after,
.nav-item > .nav-trigger:hover::after,
.nav-item > .nav-trigger[aria-current]::after,
.nav-item[data-open] > .nav-trigger::after { right: 0; }

/* One frost panel, height in --fly-h. Opening grows it from 0; moving to
   another section only retargets that height, which is how apple.com avoids
   a collapse between Mac and iPad. The lists live in per-item .fly sheets
   stacked on top, clipped to the same height, with no frost of their own. */
.fly-frame,
.fly {
  position: absolute; left: 0; right: 0; top: 100%;
  height: var(--fly-h);
  overflow: hidden;
  pointer-events: none;
  transition: height .56s var(--ease);
}
.fly-frame {
  z-index: 1;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: saturate(1.7) blur(14px);
  -webkit-backdrop-filter: saturate(1.7) blur(14px);
  box-shadow: inset 0 1px 0 var(--line), 0 1px 0 var(--line);
}
.nav:not([data-fly-open]) .fly-frame { box-shadow: none; }
.fly { z-index: 1; }
.fly[hidden] { display: none; }
.nav-item[data-open] .fly { pointer-events: auto; }
.fly-in {
  max-width: var(--shell); margin: 0 auto;
  padding: clamp(28px, 3.6vw, 44px) var(--gut) clamp(36px, 4.6vw, 56px);
  display: grid; justify-items: start; gap: 10px;
}
.fly a {
  font-size: clamp(22px, 2.1vw, 24px);
  font-weight: 600; letter-spacing: -.022em; line-height: 1.15;
  color: var(--ink);
  padding: 2px 0;
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity .22s ease;
}
.nav-item[data-open] .fly a {
  animation: fly-in .72s cubic-bezier(.16, 1, .3, 1) both;
  animation-delay: calc(.14s + var(--fly-i, 0) * .06s);
}
.nav-item[data-open][data-switch] .fly a { animation-name: fly-switch; }
.fly a:nth-child(1) { --fly-i: 0; }
.fly a:nth-child(2) { --fly-i: 1; }
.fly a:nth-child(3) { --fly-i: 2; }
.fly a:nth-child(4) { --fly-i: 3; }
.fly a:nth-child(5) { --fly-i: 4; }
.fly a:hover { color: var(--muted); }
.fly-lead { margin-bottom: 6px; }

@keyframes fly-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes fly-switch {
  from { opacity: 0; transform: translateX(8px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* Sits under the sticky bar (80) and over the page; the panel paints in the
   bar's stacking context so it stays above the dim. Apple dims, it does not
   lock scroll. */
.nav-veil {
  position: fixed; inset: var(--nav-h) 0 0; z-index: 75;
  background: rgb(10 10 11 / .32);
  opacity: 0; pointer-events: none;
  transition: opacity .45s var(--ease);
}
.nav-veil.is-on { opacity: 1; pointer-events: auto; }
.nav-veil[hidden] { display: none; }
.nav[data-fly-open] { border-bottom-color: transparent; }

.nav-quote { flex: none; }

.burger {
  display: none; margin-left: auto;
  width: 44px; height: 44px; padding: 12px 10px;
  flex-direction: column; justify-content: space-between;
}
.burger span {
  display: block; height: 1.5px; background: var(--ink); border-radius: 2px;
  transition: transform .26s var(--ease), opacity .18s var(--ease);
}
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(9px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-9px) rotate(-45deg); }

/* ------------------------------------------------------------ drawer -- */
.drawer {
  position: fixed; inset: var(--nav-h) 0 0; z-index: 70;
  background: var(--paper);
  overflow-y: auto; overscroll-behavior: contain;
}
.drawer[hidden] { display: none; }
.drawer-in {
  display: grid; gap: 2px;
  padding: 18px var(--gut) calc(28px + env(safe-area-inset-bottom));
}
.drawer-group { border-bottom: 1px solid var(--line); }
.drawer-row { display: flex; align-items: stretch; }
.drawer-row > a,
.drawer-fold {
  flex: 1;
  display: flex; align-items: center; justify-content: space-between;
  min-height: 52px;
  font-size: 21px; letter-spacing: -.02em; text-align: left;
}
.drawer-more {
  flex: none; width: 44px;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted);
}
.drawer-chev {
  width: 7px; height: 7px; margin-top: -3px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform .25s var(--ease);
}
.drawer-fold .drawer-chev { color: var(--muted); }
.drawer-more[aria-expanded="true"] .drawer-chev,
.drawer-fold[aria-expanded="true"] .drawer-chev {
  transform: rotate(225deg) translate(-1px, -1px);
}
.drawer-sub {
  display: flex; align-items: center;
  min-height: 48px; font-size: 16px; color: var(--ink-2); padding-left: 14px;
  border-top: 1px solid var(--line);
}
.drawer-quote {
  margin-top: 26px; justify-self: start; font-size: 15px;
}

/* --------------------------------------------------------------- tiles -- */
/* The apple.com arrangement: full-bleed tiles with a white gap between every
   one. The gap is the whole device — it is what turns a run of images into a
   set of cards without needing a border or a shadow anywhere.

   The copy sits ON the photograph, at the top of the tile, which is both what
   tinnox.com.au does and where Apple puts its own tile copy. */
.tiles {
  display: grid; gap: var(--gap); background: var(--paper);
  max-width: var(--stage); margin-inline: auto;
}
.tile-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap); }

.tile {
  display: grid; grid-template-rows: auto 1fr; align-content: start;
  background: var(--mist); overflow: hidden;
  container-type: inline-size;
}

.tile-copy {
  /* cqi, not vw: type and padding track the TILE, so they freeze with the
     photograph when --stage caps the stack on zoom-out. The 1.75cqi size is
     the same number the sub uses, and is what the pill's em resolves against. */
  font-size: clamp(16px, 1.75cqi, 22px);
  padding: clamp(44px, 5.4cqi, 74px) var(--gut) clamp(34px, 4cqi, 52px);
  display: grid; justify-items: center; text-align: center;
  /* px, not ch: a ch resolves against the 17px body text, not the 72px heading
     sitting inside, which stacks a three-word title three lines high. */
  max-width: min(100%, 1100px); margin: 0 auto;
}
.tile-sub {
  margin: 10px 0 0; max-width: 46ch;
  font-size: 1em; font-weight: 400;
  color: var(--ink-2); letter-spacing: -.014em;
}
.tile-acts {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 0.75em;
  margin: clamp(20px, 2.4cqi, 28px) 0 0;
}
/* Pills inside a tile follow the copy, not the 15px global. Nav and footer
   keep the px button. */
.tile-copy .btn { font-size: 0.88em; min-height: 2.75em; padding: 0 1.4em; }

/* --- a tile with the copy over the photograph ------------------------- */
/* Shape, not height.

   These were sized in vh, which tied the tile to the browser's viewport HEIGHT
   — and Safari and Chrome never agree on that, because their toolbars differ.
   Since a tile is height-constrained for object-fit: cover, a shorter window
   rescaled the whole photograph while the copy stayed put in width-based
   padding, so the words landed somewhere else on the picture. Measured on the
   kiosk page at one width: 720px tall in a 900px window against 632px in a
   790px one, a 14% difference in how zoomed the shot looked.

   An aspect-ratio resolves against the element's own layout width, so the
   framing is now a function of width alone: identical in every browser, and
   identical as the window grows and shrinks. It also sidesteps the scrollbar —
   a vw clamp would have measured 15px wider in Chrome, which has a classic
   scrollbar, than in Safari, which overlays it.

   Every ratio is the geometry measured at the reference window (1440x900),
   rounded, so nothing moves there. Height is the ratio alone: a min-height
   used to flatten zoom-in and a max-height used to flatten zoom-out, both
   of which pulled the crop off the photograph while the type stayed put. */
.tile-photo {
  position: relative; isolation: isolate;
  display: block;
  aspect-ratio: 1415 / 576;             /* tinnox.com.au's own panel box */
  width: 100%;
  container-type: inline-size;
  background: var(--night);
}
/* The paired row is half-width, so it needs its own shape or it would render
   at a third of the height the full-bleed tiles do. */
.tile-row .tile-photo { aspect-ratio: 703 / 576; }   /* theirs: 703x576 -> 1.220 */

/* The live home page does not give its five panels one height. The top LED
   Video Wall panel is min-height 32vw where every other one is 40vw — flatter
   by a quarter — and 32vw at the reference window is the native shape of this
   photograph (1920x621), so tinnox.com.au shows it uncropped edge to edge.
   At 576 tall, cover was shaving ~20% off its width. Single-class selector on
   purpose: it must lose to the phone rule below, which resets every tile to
   the stacked portrait shape. The floor drops with the ratio so the panel
   stays visibly flatter than its neighbours in a narrow window. */
.tile-wall { aspect-ratio: 1415 / 461; }   /* theirs: 32vw */
.tile-photo .tile-shot { position: absolute; inset: 0; z-index: -2; }
.tile-photo .tile-shot picture { display: block; width: 100%; height: 100%; }
.tile-photo .tile-shot img { width: 100%; height: 100%; object-fit: cover; }

/* The home page keeps no overlay at all: its five photographs are either dark
   enough already or their bright areas fall away from the words. The shadow on
   the glyphs is all it needs, and it costs the picture nothing. */
.tile-photo .display,
.tile-photo .tile-sub {
  text-shadow: 0 1px 3px rgb(8 10 14 / .55), 0 2px 26px rgb(8 10 14 / .62);
}
.tile-photo .display    { font-size: clamp(34px, 5cqi, 72px); }
.tile-photo .display-sm { font-size: clamp(30px, 3.4cqi, 50px); }

/* Product photo tiles follow tinnox.com.au's Elementor sizes: h2 32px,
   body 16px, size-sm buttons 15px / 12px 24px / 20px radius, white Learn More.
   Home plus LED Video Wall / Digital Kiosk / LED Hire. The projects gallery
   and the quote gradient hero stay on their own type. */
.tiles:not(.tiles-projects) .tile-photo .tile-copy { font-size: 16px; }
.tiles:not(.tiles-projects) .tile-photo .display,
.tiles:not(.tiles-projects) .tile-photo .display-sm { font-size: 32px; }
.tiles:not(.tiles-projects) .tile-photo .tile-copy .btn {
  font-size: 15px; font-weight: 500; line-height: 1;
  min-height: 40px; padding: 12px 24px; border-radius: 20px;
}
.tiles:not(.tiles-projects) .tile-photo .btn-on-image {
  color: var(--navy); background: #fff; border-color: #fff;
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.tiles:not(.tiles-projects) .tile-photo .btn-on-image:hover {
  color: var(--navy); background: #e6e6e6; border-color: #e6e6e6;
}
.tiles:not(.tiles-projects) .tile-photo .btn-solid { border-color: var(--navy); }

/* --- the interior product pages -------------------------------------- */
/* LED Video Wall, Digital Kiosk and LED Hire are catalogues: four variants
   of one product, read in a scroll. Type and buttons share the home tiles'
   Elementor sizes above. What stays different is the tile shape and the
   per-photograph gradient, so the screens in these shots stay bright. */
.tiles-compact .tile-photo { aspect-ratio: 1415 / 576; }
.tiles-compact .display    { font-size: clamp(28px, 3.4cqi, 48px); }
.tiles-compact .display-sm { font-size: clamp(26px, 2.8cqi, 38px); }
.tiles-compact .tile-copy  {
  font-size: clamp(15px, 1.5cqi, 18px);
  padding-top: clamp(38px, 4.2cqi, 62px);
}
.tiles-compact .tile-sub   { margin-top: 8px; }
.tiles-compact .tile-acts  { margin-top: clamp(18px, 2cqi, 24px); }

/* Digital Kiosk and LED Hire have the screen high in almost every frame — the
   bright band sits at 7-25% of the tile on most of them, which is exactly where
   the copy was. Two changes pull them apart, and they compound: a taller tile
   with a bottom-anchored crop reveals more of the image above the subject, which
   pushes the screen further down the frame, and less padding lifts the copy off
   the top of it. Neither touches the picture. */
.tiles-tall .tile-photo { aspect-ratio: 1415 / 576; }
.tiles-tall .tile-copy  { padding-top: clamp(24px, 2.6cqi, 38px); }

/* A couple of photographs put the screen higher still — Entrance Signage and
   Carpark both frame it near the top edge. Height is per tile as well as per
   page for those, rather than pushing every tile on the page out to suit two. */
.tile-photo.is-xtall           { aspect-ratio: 1415 / 576; }
.tile-photo.is-xtall .tile-copy { padding-top: clamp(18px, 2cqi, 28px); }
.tile-photo.is-xtall::before {
  background: linear-gradient(180deg,
    rgb(8 10 14 / calc(var(--scrim) * 1.04)) 0%,
    rgb(8 10 14 / var(--scrim)) 24%,
    rgb(8 10 14 / 0) 42%);
}

/* The Digital Billboard shot is the one frame where the gradient cannot run as
   far as the others. On tinnox.com.au's own panel shape the Carlton-Richmond
   banner sits across 21%-40% of the crop — higher in frame than it was in the
   taller box — and the shared gradient is still fading at 56%, so it would lay
   a veil over the whole screen being sold. This clears by 20%, just above the
   banner, leaving the screen completely untouched. The live site runs no
   overlay on this panel at all, and its copy sits over the banner exactly as
   ours does; the photograph is dark enough up top to carry the type without
   help, which the contrast numbers confirm.

   Three classes rather than an !important, so the phone rule further down can
   still override it if it ever needs to. It does not today: a narrow tile
   stacks the buttons and pushes the copy down, but only to 33%, and the band
   sits lower in frame there too (38%), so one gradient serves both widths. */
.tiles-tall .tile-photo.tile-billboard::before {
  background: linear-gradient(180deg,
    rgb(8 10 14 / calc(var(--scrim) * 1.04)) 0%,
    rgb(8 10 14 / var(--scrim)) 12%,
    rgb(8 10 14 / 0) 20%);
}

/* Finishing higher means the gradient can stop sooner still — half of every one
   of these photographs is now completely untouched. */
.tiles-tall .tile-photo::before {
  background: linear-gradient(180deg,
    rgb(8 10 14 / calc(var(--scrim) * 1.04)) 0%,
    rgb(8 10 14 / var(--scrim)) 30%,
    rgb(8 10 14 / 0) 50%);
}

.tiles-compact .tile-photo::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg,
    rgb(8 10 14 / calc(var(--scrim) * 1.04)) 0%,
    rgb(8 10 14 / var(--scrim)) 36%,
    rgb(8 10 14 / 0) 56%);
}

/* Measured per photograph against the pixels the copy actually lands on — the
   alpha that carries white type to 4.5:1 there, and no more. */
.tile-retail      { --scrim: .40; }
.tile-education   { --scrim: .52; }
.tile-pylon       { --scrim: .56; }
.tile-billboard   { --scrim: .52; }
.tile-public      { --scrim: .47; }
.tile-indoor      { --scrim: .52; }
.tile-entrance    { --scrim: .52; }
.tile-carpark     { --scrim: .51; }
.tile-activations { --scrim: .56; }
.tile-expos       { --scrim: .49; }
.tile-corporate   { --scrim: .52; }
.tile-stage       { --scrim: .18; }   /* already a night shot */

/* Projects gallery: twelve rounded squares in the shell, three across,
   so they read as a set of cards rather than another full-bleed poster wall. */
.tiles-projects {
  --scrim: .50;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(16px, 2.2vw, 28px);
}
.tiles-projects.tiles-compact .tile-photo {
  aspect-ratio: 1 / 1;
  border-radius: 20px;
}
.tiles-projects .tile-copy {
  padding: clamp(18px, 3.4cqi, 28px) clamp(14px, 3cqi, 22px) 0;
}
.tiles-projects.tiles-compact .display-sm {
  font-size: clamp(18px, 3.8cqi, 26px);
}
.proj-brady        { --scrim: .50; }
.proj-ecu          { --scrim: .48; }
.proj-strand       { --scrim: .55; }
.proj-apollo       { --scrim: .52; }
.proj-markets      { --scrim: .48; }
.proj-transmission { --scrim: .18; }
.proj-yarra        { --scrim: .50; }
.proj-kitkat       { --scrim: .52; }
.proj-ao           { --scrim: .50; }
.proj-citybeach    { --scrim: .48; }
.proj-madman       { --scrim: .32; }
.proj-iga          { --scrim: .56; }
.proj-brady        .tile-shot img { object-position: 50% 42%; }
.proj-ecu          .tile-shot img { object-position: 50% 50%; }
.proj-strand       .tile-shot img { object-position: 50% 45%; }
.proj-apollo       .tile-shot img { object-position: 50% 50%; }
.proj-markets      .tile-shot img { object-position: 55% 40%; }
.proj-transmission .tile-shot img { object-position: 50% 50%; }
.proj-yarra        .tile-shot img { object-position: 22% 50%; }
.proj-kitkat       .tile-shot img { object-position: 50% 42%; }
.proj-ao           .tile-shot img { object-position: 40% 50%; }
.proj-citybeach    .tile-shot img { object-position: 72% 50%; }
.proj-madman       .tile-shot img { object-position: 50% 42%; }
.proj-iga          .tile-shot img { object-position: 50% 42%; }

.proj-close .statement {
  text-align: center; max-width: 18ch; margin-inline: auto;
}
.proj-close p {
  margin: 16px auto 0; max-width: 46rem;
  text-align: center; color: var(--ink-2);
}

.tile-photo .tile-copy { position: relative; }
.tile-photo .tile-sub { color: rgba(255, 255, 255, .92); }

/* White type on every tile that carries an image behind it. */
.tile-photo .display, .tile-gradient .display,
.tile-photo .tile-copy, .tile-gradient .tile-copy { color: #fff; }

/* Each photograph gets its own crop anchor so the subject survives a tile that
   is a different shape from the file. */
.tile-wall    .tile-shot img { object-position: 50% 52%; }
.tile-kiosk   .tile-shot img { object-position: 50% 62%; }
.tile-outdoor .tile-shot img { object-position: 50% 46%; }
.tile-mto     .tile-shot img { object-position: 50% 56%; }
.tile-hire    .tile-shot img { object-position: 50% 50%; }
/* The live page bottom-anchors all four of these, and it is right to: the
   screens are in the lower half of every one of these photographs. */
.tile-retail    .tile-shot img { object-position: 50% 100%; }
.tile-education .tile-shot img { object-position: 50% 100%; }
.tile-pylon     .tile-shot img { object-position: 50% 100%; }
.tile-billboard .tile-shot img { object-position: 50% 100%; }
.tile-public    .tile-shot img { object-position: 50% 100%; }
.tile-indoor    .tile-shot img { object-position: 50% 100%; }
.tile-entrance  .tile-shot img { object-position: 50% 100%; }
.tile-carpark   .tile-shot img { object-position: 50% 100%; }
/* led hire page — these follow the live site's own per-panel anchors. Expos is
   bottom-anchored on purpose: centred, the crop cuts the F1 car out of frame. */
.tile-activations .tile-shot img { object-position: 50% 50%; }
.tile-expos       .tile-shot img { object-position: 50% 100%; }
.tile-corporate   .tile-shot img { object-position: 50% 50%; }
.tile-stage       .tile-shot img { object-position: 50% 50%; }

/* The quote page's header is the same tile, with the supplied gradient as its
   ground instead of the usual grey. Near-black type on it, not the live site's
   white: white lands around 1.9:1 on a pastel and cannot be read, and dimming
   the image to rescue it would break the no-filter rule the tiles above set. */
.tile-gradient {
  background: url("/assets/img/led-digital-signage-cost-hire-quote.jpg") 50% 50% / cover no-repeat var(--mist);
  min-height: clamp(200px, 22vw, 290px);
  align-content: center;
}
.tile-gradient .tile-copy { padding-block: clamp(30px, 4vw, 48px); }

.crumb {
  margin: 14px 0 0; font-size: 13.5px;
  color: rgba(255, 255, 255, .88);
  display: flex; align-items: center; gap: 9px;
}
.crumb a { text-decoration: underline; text-underline-offset: 3px; }
.crumb a:hover { color: #fff; }
.opener .crumb { color: var(--muted); justify-content: center; }
.opener .crumb a:hover { color: var(--ink); }

/* --------------------------------------------------------------- band -- */
.band { padding: var(--band) 0; }
.band + .band { padding-top: 0; }

/* Homepage bands (Clients, Projects, FAQ, Articles) follow tinnox.com.au:
   a 1rem section name over a 2.5rem statement. Other pages still use a
   large title over a muted line. */
.band-head {
  display: grid; justify-items: center; text-align: center;
  gap: 14px; margin-bottom: clamp(40px, 5vw, 68px);
}
.band-head:has(.band-kicker) { gap: 20px; }
.band-kicker {
  margin: 0;
  font-size: 1rem; font-weight: 500; line-height: 1.1;
  letter-spacing: -.012em;
}
.band-sub {
  margin: 0; max-width: 46ch;
  font-size: clamp(15.5px, 1.6vw, 18px); color: var(--muted);
}
.band-head:has(.band-kicker) .statement {
  font-size: clamp(28px, 3.2vw, 40px);
  letter-spacing: -.04em;
}

/* ------------------------------------------------------ page opener -- */
/* Measured off the live page rather than guessed at. tinnox.com.au hides its
   own dark title strip with an inline script, so what the industries pages
   actually open with is a small centred line naming the page, a large centred
   statement, and a hairline: 19px / 59px / 791px wide at a 1440 viewport.
   That is reproduced here in our type. */
.opener {
  padding-top: clamp(40px, 5vw, 76px);
  display: grid; justify-items: center; text-align: center;
  gap: clamp(12px, 1.4vw, 20px);
}
.opener-kicker {
  margin: 0; font-weight: 400; letter-spacing: -.012em;
  font-size: clamp(16px, 1.35vw, 19px); color: var(--ink);
}
.opener-statement {
  margin: 0; max-width: min(100%, 1120px); text-wrap: balance;
  font-size: clamp(31px, 4.2vw, 59px);
  font-weight: 600; letter-spacing: -.022em; line-height: 1.2;
}
/* The live rule is 791px of #888 under a 1120px container. Ours keeps the
   proportion against our own shell and uses the hairline already in the
   palette. */
.opener-rule {
  width: min(100%, 790px); height: 1px; border: 0;
  margin: clamp(26px, 3.2vw, 48px) 0 0; background: var(--line-2);
}
.opener-lead {
  margin: 0; max-width: 42rem;
  font-size: clamp(16.5px, 1.25vw, 19.2px);
  line-height: 1.45; color: var(--ink-2);
}
.opener.proj-opener { padding-bottom: clamp(40px, 5vw, 72px); }

/* --------------------------------------------------- editorial band -- */
/* The arrangement is the live page's, measured at 1440: the heading takes
   about seven tenths of the container and the line beside it about three,
   set small, light, grey and flush RIGHT so it reads as a margin note rather
   than a second heading. The paragraph then runs the full width beneath both
   of them, and the photographs run beneath that.

   Only the typeface, weights and colours are ours. */
.ed { padding: clamp(56px, 7vw, 104px) 0 0; }

.ed-head {
  display: grid; grid-template-columns: 2.33fr 1fr;
  gap: clamp(20px, 2.6vw, 48px); align-items: start;
}
.ed-title {
  margin: 0; text-wrap: balance;
  font-size: clamp(28px, 3.1vw, 44px);
  font-weight: 600; letter-spacing: -.024em; line-height: 1.08;
}
.ed-lede {
  margin: 0; text-align: right;
  /* Nudged down so it sits with the heading's first line rather than its
     cap-height, which is what the live page's 10px offset does. */
  padding-top: clamp(4px, .6vw, 9px);
  font-size: clamp(14.5px, 1.25vw, 16.5px); font-weight: 400;
  letter-spacing: -.008em; line-height: 1.45; color: var(--muted);
}
.ed-body {
  margin: clamp(20px, 2.4vw, 34px) 0 0;
  font-size: 17px; line-height: 1.64; color: var(--ink-2);
}

/* The CTA carries equal 60px above and below the heading+button. Neighbours
   must not add their own pad or the group sits off-centre — articles used to
   sit it low, LED Hire's gallery used to sit it high. */
:is(.band, .ed, .art-body):has(+ .cta) { padding-bottom: 0; }
.cta + .band { padding-top: 0; }
/* Hire gallery is a grey slab after the white CTA, so it keeps its own pad. */
.cta + .band-gallery { padding-top: var(--band); }

.ed-shots {
  /* 20px, which is the live page's gutter between the paired shots — not the
     12px white line, which belongs to the full-bleed tiles. */
  display: grid; gap: 20px;
  max-width: var(--shell); margin: clamp(30px, 3.8vw, 54px) auto 0;
  padding: 0 var(--gut);
}
.ed-shots-2 { grid-template-columns: 1fr 1fr; }
.ed-shots figure {
  margin: 0; border-radius: 14px; overflow: hidden; background: var(--mist);
}
.ed-shots picture { display: block; width: 100%; height: 100%; }
.ed-shots img { width: 100%; height: 100%; object-fit: cover; }
/* These are the masters' own ratios — the paired shots are square and the
   single ones are 2:1 — so cover crops nothing, and the box is the right
   size before the image arrives. */
.ed-shots-2 figure { aspect-ratio: 1 / 1; }
.ed-shots-1 figure { aspect-ratio: 2 / 1; }

/* ------------------------------------------------------- ISO certs -- */
/* Measured off tinnox.com.au/iso-certifications/ at 1440.

   The live page opens on #F6F6F6: a small line, a 3.7em centred title, and
   the lead underneath. Then three cards, each a grey copy pane (14% pad,
   20px radius on the left) joined to the square badge (20px on the right)
   with no gutter between them. */
.iso-hero { background: var(--mist); }
.iso-hero .opener {
  padding-top: clamp(36px, 4.4vw, 56px);
  padding-bottom: clamp(48px, 6vw, 88px);
}
.iso-lead {
  margin: clamp(16px, 2vw, 28px) auto 0;
  max-width: 46rem;
  font-size: clamp(16.5px, 1.25vw, 19.2px);
  line-height: 1.45; color: var(--ink-2);
}
.iso-rows {
  max-width: var(--shell); margin: 0 auto;
  padding: clamp(48px, 6vw, 80px) var(--gut) 0;
  display: grid; gap: clamp(56px, 7vw, 96px);
}
.iso-card {
  display: grid; grid-template-columns: 1fr 1fr;
  border-radius: 20px; overflow: hidden;
  background: var(--mist);
}
.iso-copy {
  padding: 14%;
  display: grid; align-content: center;
}
.iso-copy h2 {
  margin: 0 0 16px; text-wrap: balance;
  font-size: clamp(26px, 2.6vw, 40px);
  font-weight: 600; letter-spacing: -.022em; line-height: 1.15;
  color: var(--ink-2);
}
.iso-copy p {
  margin: 0;
  font-size: clamp(16.5px, 1.3vw, 20.8px);
  font-weight: 500; line-height: 1.45; color: var(--ink);
}
.iso-shot {
  margin: 0; background: #000;
  aspect-ratio: 1 / 1; height: 100%;
}
.iso-shot img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  display: block;
}
.iso-close {
  margin: clamp(48px, 6vw, 80px) auto 0;
  max-width: 46rem; padding: 0 var(--gut);
  text-align: center;
  font-size: clamp(16.5px, 1.25vw, 19.2px);
  line-height: 1.45; color: var(--ink-2);
}
.iso-rule {
  width: min(70%, 790px); height: 1px; border: 0;
  margin: clamp(36px, 4vw, 56px) auto 0; background: var(--line-2);
}

/* Ethics reuses the ISO cards. The opener adds a pull-quote; the first
   card is two copy panes (mist + a slightly darker grey) instead of a photo. */
.eth-quote {
  margin: clamp(24px, 3vw, 40px) auto 0;
  max-width: none;
  border: 0; padding: 0;
  font-style: normal;
}
.eth-quote p {
  margin: 0;
  font-size: clamp(16px, 1.7vw, 25.6px);
  font-weight: 500; line-height: 1.4; color: var(--ink);
}
.eth-quote footer {
  margin-top: 10px;
  font-size: clamp(16px, 1.7vw, 25.6px);
  font-weight: 500; color: var(--ink);
}
@media (min-width: 768px) {
  .eth-quote p { white-space: nowrap; }
}
.iso-copy-alt { background: #e7e7e7; }
/* Live Accountability card uses 6% vertical pad so the longer heading
   still sits in a square that matches the Values photograph beside it. */
.iso-copy-snug { padding: 6% 14%; }

/* ------------------------------------------------------- warranty -- */
/* Live product-warranty is a dark overlay hero, a red PDF button, four
   bordered chips and a black SLA table. Same order here; Apple temperature. */
.opener.war-opener { padding-bottom: clamp(40px, 5vw, 72px); }
.opener.war-opener .opener-lead { max-width: 56rem; }
/* One column for chips, policy, cards and the SLA table, plus gutters so
   it lines up with the opener lead. */
.war {
  width: min(100%, calc(56rem + 2 * var(--gut)));
  margin: 0 auto;
  padding: 0 var(--gut) clamp(48px, 6vw, 80px);
}
.war-head {
  margin-bottom: clamp(28px, 3.6vw, 44px);
  text-align: center;
}
.war-head h2 {
  margin: 0; text-wrap: balance;
  font-size: clamp(22px, 2.4vw, 32px);
  font-weight: 600; letter-spacing: -.022em; line-height: 1.15;
}
.war-series {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin: 0 0 clamp(48px, 6vw, 80px);
}
.war-chip {
  margin: 0; padding: 18px 14px;
  background: var(--mist); border-radius: 20px;
  text-align: center;
  font-size: 15px; font-weight: 500; letter-spacing: -.014em;
}
.war-sec {
  margin: 0 0 clamp(40px, 5vw, 64px);
}
.war-sec h3 {
  margin: 0 0 14px;
  font-size: clamp(20px, 2vw, 26px);
  font-weight: 600; letter-spacing: -.02em; line-height: 1.2;
}
.war-sec p { margin: 0 0 12px; color: var(--ink-2); }
.war-sec p:last-child { margin-bottom: 0; }
.war-sec ol, .war-card ol {
  margin: 12px 0 0; padding-left: 1.25em; color: var(--ink-2);
}
.war-sec li, .war-card li { margin: 0 0 10px; }
.war-sec li:last-child, .war-card li:last-child { margin-bottom: 0; }
.war-sec ol ol { margin: 8px 0 0; }
.war-pair {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(16px, 2vw, 24px);
  margin: 0 0 clamp(40px, 5vw, 64px);
}
.war-card {
  background: var(--mist); border-radius: 20px;
  padding: clamp(24px, 3vw, 36px);
}
.war-card h3 {
  margin: 0 0 12px;
  font-size: clamp(18px, 1.8vw, 22px);
  font-weight: 600; letter-spacing: -.02em; line-height: 1.2;
}
.war-card p { margin: 0 0 12px; color: var(--ink-2); }
.war-card ol { margin: 0; }
.war-table-wrap { overflow-x: auto; }
.war-table {
  width: 100%; border-collapse: collapse;
  font-size: 15px; line-height: 1.45;
}
.war-table th, .war-table td {
  border: 1px solid var(--line);
  padding: 14px 16px; vertical-align: top; text-align: left;
}
.war-table th {
  background: var(--mist);
  font-weight: 600; letter-spacing: -.014em;
}
.war-table ul {
  margin: 8px 0 0; padding-left: 1.15em; color: var(--ink-2);
}
.war-table td p { margin: 8px 0 0; color: var(--ink-2); }
.war-note {
  margin: 16px 0 0;
  font-size: 14px; color: var(--muted);
}

/* ----------------------------------------------------------- article -- */
/* Apple Newsroom: kicker + date, a large title, a dek, a wide figure, then
   a narrower reading measure. Copy-text / download-media is a press kit;
   these are industry pieces, so that band is out. */
.opener.art-opener { padding-bottom: clamp(28px, 3.4vw, 48px); }
.opener.art-opener .opener-statement {
  max-width: 18em;
  font-size: clamp(28px, 3.6vw, 48px);
}
.opener.art-opener .opener-lead { max-width: 40rem; }
.art-kicker {
  margin: 0;
  font-size: 12px; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted);
}
.art-hero {
  width: min(100%, calc(56rem + 2 * var(--gut)));
  margin: 0 auto clamp(36px, 4.6vw, 64px);
  padding: 0 var(--gut);
}
.art-hero img {
  display: block; width: 100%; height: auto;
  border-radius: 20px; background: var(--mist);
}
.art-hero figcaption {
  margin: 10px 0 0;
  font-size: 13px; line-height: 1.4; color: var(--muted);
  text-align: center;
}
.art-body {
  width: min(100%, calc(40rem + 2 * var(--gut)));
  margin: 0 auto;
  padding: 0 var(--gut) clamp(48px, 6vw, 80px);
  font-size: clamp(16.5px, 1.2vw, 18px);
  line-height: 1.55; color: var(--ink-2);
}
.art-body p { margin: 0 0 1.1em; }
.art-body ul { margin: 0 0 1.1em; padding-left: 1.2em; }
.art-body li { margin: 0 0 8px; }
.art-body li:last-child { margin-bottom: 0; }
.art-body p:last-child,
.art-body ul:last-child { margin-bottom: 0; }

/* ------------------------------------------------------------- legal -- */
/* Live privacy / terms are a WordPress stack of H5s. Same copy here, broken
   into mist cards so the page is a set of tiles rather than a wall of type. */
.opener.legal-opener { padding-bottom: clamp(32px, 4vw, 56px); }
.opener.legal-opener .opener-statement { max-width: 12em; }
.legal {
  width: min(100%, calc(56rem + 2 * var(--gut)));
  margin: 0 auto;
  padding: 0 var(--gut) clamp(48px, 6vw, 80px);
  display: grid;
  gap: clamp(12px, 1.6vw, 20px);
}
.legal-pair {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(12px, 1.6vw, 20px);
}
.legal-card {
  background: var(--mist); border-radius: 20px;
  padding: clamp(24px, 3vw, 36px);
}
.legal-n {
  display: block; margin: 0 0 8px;
  font-family: var(--mono); font-size: 11px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--muted);
}
.legal-card h2 {
  margin: 0 0 12px;
  font-size: clamp(18px, 1.8vw, 22px);
  font-weight: 600; letter-spacing: -.02em; line-height: 1.2;
}
.legal-card p { margin: 0 0 12px; color: var(--ink-2); }
.legal-card p:last-child { margin-bottom: 0; }
.legal-card ul {
  margin: 0; padding-left: 1.2em; color: var(--ink-2);
}
.legal-card li { margin: 0 0 8px; }
.legal-card li:last-child { margin-bottom: 0; }
.legal a {
  color: var(--ink);
  text-decoration: underline; text-decoration-thickness: 1px;
  text-decoration-color: var(--line-2); text-underline-offset: 3px;
}
.legal a:hover { color: var(--navy); text-decoration-color: currentColor; }

/* ------------------------------------------------------------- logos -- */
/* Six across suits the home page's twelve marks. Eight would leave an orphan
   row of two, so a set of that size gets four across and two even rows. Scoped
   to the wide breakpoint only, so the narrower rules below still apply to it —
   an !important here would have overridden every one of them. */
@media (min-width: 1080px) {
  .logos.logos-4 { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 1079px) {
  .tiles-projects { grid-template-columns: repeat(2, 1fr); }
  .war-series { grid-template-columns: 1fr 1fr; }
}

.logos {
  display: grid; grid-template-columns: repeat(6, 1fr);
  gap: clamp(20px, 3vw, 44px) clamp(16px, 2.4vw, 36px);
  align-items: center;
}
/* Each mark is fitted into a box rather than set to a fixed height. The build
   script normalises every logo to the same pixel height, so a uniform CSS
   height makes Telstra three times the area of Nestlé. Letting a wide mark hit
   the box's width first and a square one hit its height evens the optical
   weight out, which is the thing the eye is actually reading. */
.logos li { display: grid; place-items: center; }
.logos img {
  width: auto; height: auto;
  /* Absolute, not 100%: a percentage max-height resolves against the grid area,
     which is itself sized by this image, so the cap never binds. */
  max-width: 100%; max-height: clamp(42px, 4.6vw, 60px);
  /* One flat ink with alpha, so the row's weight is this single number. Full
     black at logo scale reads louder than the headings do. */
  opacity: .48;
  transition: opacity .22s var(--ease);
}
.logos li:hover img { opacity: .82; }

/* -------------------------------------------------------------- reel -- */
/* Apple's Endless entertainment gallery, at our scale. The stage runs the full
   page width; the current film is centred in it and the neighbours show at
   both edges, so the row reads as something you can slide rather than as a
   single picture that happens to change. */
.reel { --slide-w: min(920px, 78vw); position: relative; }

.reel-stage { position: relative; overflow: hidden; }

/* The row loops, so it is not a strip that slides — each slide carries its own
   offset from centre and wraps around, which is how apple.com's gallery does
   it too. That is what lets the first film have a neighbour on its left: the
   last one is sitting there. */
.reel-track { position: relative; height: calc(var(--slide-w) * 9 / 16); }

.slide {
  position: absolute; top: 0; left: 50%;
  width: var(--slide-w); aspect-ratio: 16 / 9;
  transform: translateX(calc(-50% + var(--r, 0) * (var(--slide-w) + var(--gap))));
  transition: transform .62s var(--ease), opacity .5s var(--ease);
  background: var(--night);
  /* The one thing kept from our own system rather than Apple's: the corner
     radius that the article cards and the tiles' media already use. */
  border-radius: 14px; overflow: hidden;
}
.slide[hidden] { display: none; }          /* the no-JS fallback: one slide */
.slide img { width: 100%; height: 100%; object-fit: cover; }

/* The peeked neighbours are visible but not live — dimmed so the eye knows
   which one it is being offered, and inert so a half-visible play button
   cannot be hit by accident. */
.reel.is-live .slide { opacity: .45; pointer-events: none; }
.reel.is-live .slide.is-current { opacity: 1; pointer-events: auto; }
/* Set while a slide is being teleported from one end of the loop to the other,
   which must never be animated. */
.slide.is-jumping { transition: none; }

.play {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: grid; place-items: center;
  background: rgba(8, 10, 14, .18);
  transition: background .25s var(--ease);
}
.play:hover { background: rgba(8, 10, 14, .34); }
.play-tri {
  width: clamp(54px, 5vw, 72px); aspect-ratio: 1; border-radius: 50%;
  background: rgba(255, 255, 255, .94);
  box-shadow: 0 10px 34px rgba(0, 0, 0, .3);
  transition: transform .25s var(--ease);
  display: grid; place-items: center;
}
.play:hover .play-tri { transform: scale(1.06); }
.play-tri::after {
  content: ""; margin-left: 4px;
  border-left: 15px solid var(--ink);
  border-top: 9.5px solid transparent; border-bottom: 9.5px solid transparent;
}

.slide iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Sat over the peeked neighbours, where Apple puts them. */
.reel-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 46px; height: 46px; border-radius: 50%;
  background: rgba(255, 255, 255, .92);
  display: none; place-items: center;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .16);
  transition: background .2s var(--ease), transform .2s var(--ease);
}
.reel.is-live .reel-arrow { display: grid; }
.reel-arrow:hover { background: #fff; }
.reel-arrow::before {
  content: ""; width: 9px; height: 9px;
  border-top: 1.6px solid var(--ink); border-right: 1.6px solid var(--ink);
}
.reel-prev { left: max(16px, calc((100% - var(--slide-w)) / 2 - 62px)); }
.reel-prev::before { transform: rotate(-135deg); margin-left: 3px; }
.reel-next { right: max(16px, calc((100% - var(--slide-w)) / 2 - 62px)); }
.reel-next::before { transform: rotate(45deg); margin-right: 3px; }

/* Apple's dotnav: a capsule of dots where the current one stretches into a bar
   rather than merely changing colour. */
.reel-dots {
  display: flex; justify-content: center; align-items: center; gap: 8px;
  width: max-content; margin: 26px auto 0;
  padding: 5px 9px; border-radius: 999px; background: var(--mist);
}
.reel-dots button {
  width: 24px; height: 24px; display: grid; place-items: center;
}
.reel-dots button::after {
  content: ""; display: block; width: 7px; height: 7px; border-radius: 999px;
  background: var(--line-2);
  transition: width .32s var(--ease), background .2s var(--ease);
}
.reel-dots button[aria-current="true"] { width: 34px; }
.reel-dots button[aria-current="true"]::after { width: 22px; background: var(--ink); }
.reel-dots button:hover::after { background: var(--muted); }
/* No pause control: nothing here moves unless somebody moves it, so there is
   nothing to stop. */

/* ---------------------------------------------------------------- qa -- */
.qas { max-width: 900px; margin: 0 auto; border-top: 1px solid var(--line); }
.qa { border-bottom: 1px solid var(--line); }

.qa summary {
  display: flex; align-items: baseline; gap: clamp(14px, 2vw, 26px);
  padding: clamp(20px, 2.4vw, 26px) 0;
  cursor: pointer; list-style: none;
}
.qa summary::-webkit-details-marker { display: none; }
.qa-n {
  flex: none; font-family: var(--mono); font-size: 11.5px;
  letter-spacing: .1em; color: var(--muted); padding-top: 4px;
}
.qa-q {
  flex: 1; font-size: clamp(17px, 1.9vw, 21px); font-weight: 500;
  letter-spacing: -.019em; line-height: 1.35;
  transition: color .18s var(--ease);
}
.qa summary:hover .qa-q { color: var(--navy); }

/* A plus that becomes a minus — cheaper to read than a rotating chevron. */
.qa-mark { position: relative; flex: none; width: 14px; height: 14px; align-self: center; }
.qa-mark::before, .qa-mark::after {
  content: ""; position: absolute; inset: 50% 0 auto 0;
  height: 1.5px; background: var(--ink-2);
  transition: transform .26s var(--ease);
}
.qa-mark::after { transform: rotate(90deg); }
.qa[open] .qa-mark::after { transform: rotate(0deg); }

.qa-a {
  padding: 0 0 clamp(22px, 2.4vw, 28px);
  padding-left: calc(clamp(14px, 2vw, 26px) + 32px);
  max-width: 74ch;
}
.qa-a p { margin: 0; font-size: 16px; color: var(--ink-2); }
/* Several answers link out mid-sentence, and the reset up top strips every
   underline, so without this the links would be invisible inside the run of
   text they sit in. */
.qa-a a {
  color: var(--ink);
  text-decoration: underline; text-decoration-thickness: 1px;
  text-decoration-color: var(--line-2); text-underline-offset: 3px;
  transition: color .18s var(--ease), text-decoration-color .18s var(--ease);
}
.qa-a a:hover { color: var(--navy); text-decoration-color: currentColor; }

/* ------------------------------------------------------------- cards -- */
.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 35px 10px; }

/* Live posts (widget 0260a7c): 20px corners, #F5F5F5 fill, Read More on the
   right. Titles still run to two or three lines; the excerpt takes the slack
   so the three links sit on one row. */
.cards li { display: grid; }
.card {
  display: grid; grid-template-rows: auto 1fr;
  background: #F5F5F5; border-radius: 20px; overflow: hidden;
}
.card-shot {
  display: block; overflow: hidden;
  background: #F5F5F5; aspect-ratio: 3 / 2;
}
.card-shot picture { display: block; width: 100%; height: 100%; }
.card-shot img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .5s var(--ease);
}
.card:hover .card-shot img { transform: scale(1.035); }

.card-body {
  display: grid; grid-template-rows: auto 1fr auto; gap: 12px;
  padding: 20px 24px 28px;
}
.card-title {
  margin: 0; font-size: clamp(18px, 1.8vw, 21px); font-weight: 500;
  letter-spacing: -.021em; line-height: 1.25;
}
.card-text {
  font-size: 15px; color: var(--muted); line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.card-more {
  justify-self: end;
  font-size: 14px; font-weight: 500; color: var(--ink);
}
.card-more [aria-hidden] { display: none; }
.card-more::after { content: " >"; }
.card:hover .card-more { color: var(--navy); }

/* ------------------------------------------------------------ gallery -- */
/* Rental Installations. The live page packs these into ten tiny columns with a
   1px gutter; here they get the article cards' proportions and corner radius,
   so the grid belongs to the same family as everything else on the site. */
.band-gallery { background: #F5F5F5; }
.gallery {
  display: grid; grid-template-columns: repeat(5, 1fr);
  gap: clamp(10px, 1.2vw, 16px);
}
.shot {
  display: block; width: 100%; padding: 0;
  aspect-ratio: 4 / 3; overflow: hidden; border-radius: 12px;
  background: var(--mist); cursor: zoom-in;
}
.shot picture { display: block; width: 100%; height: 100%; }
.shot img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .5s var(--ease), opacity .3s var(--ease);
}
.shot:hover img { transform: scale(1.06); }

/* ----------------------------------------------------------- lightbox -- */
/* Apple's treatment: the page goes dark and out of focus behind, the picture
   sits alone in the middle at whatever size fits. The arrows are the carousel's
   own, so there is one round arrow button on this site, not two. */
.lightbox {
  position: fixed; inset: 0; z-index: 120;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: clamp(8px, 2vw, 28px); padding: clamp(12px, 3vw, 40px);
  background: rgb(8 10 14 / .93);
  backdrop-filter: blur(22px) saturate(1.2);
  -webkit-backdrop-filter: blur(22px) saturate(1.2);
  animation: lb-in .22s var(--ease);
}
.lightbox[hidden] { display: none; }
@keyframes lb-in { from { opacity: 0 } to { opacity: 1 } }

/* No explicit grid-row here. A definitely-placed item is positioned before the
   auto-placed ones, so naming the row made the figure claim column 1 and pushed
   both arrows to its right. Letting all three auto-place puts them in DOM order:
   arrow, picture, arrow. */
.lb-stage {
  margin: 0; min-width: 0; display: grid; justify-items: center; gap: 14px;
}
.lb-stage img {
  max-width: 100%; max-height: calc(100dvh - 150px);
  width: auto; border-radius: 14px;
  background: var(--night);
}
.lb-cap {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  justify-content: center; text-align: center;
  font-size: 13.5px; color: rgba(255, 255, 255, .82);
}
.lb-count { font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em; color: rgba(255, 255, 255, .5); }

/* The arrows sit in the grid's outer columns rather than over the picture, so
   they never cover the thing you opened. */
.lightbox .reel-arrow { position: static; transform: none; display: grid; }

.lb-close {
  position: absolute; top: clamp(10px, 2vw, 22px); right: clamp(10px, 2vw, 22px);
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .12); color: #fff;
  transition: background .2s var(--ease);
}
.lb-close:hover { background: rgba(255, 255, 255, .24); }
.lb-close::before {
  content: ""; width: 15px; height: 15px; background: currentColor;
  clip-path: polygon(14% 0, 50% 36%, 86% 0, 100% 14%, 64% 50%, 100% 86%, 86% 100%, 50% 64%, 14% 100%, 0 86%, 36% 50%, 0 14%);
}

/* ---------------------------------------------------------- quote page -- */
.band-quote .band-head { margin-bottom: clamp(30px, 3.4vw, 44px); }
.band-quote .statement { max-width: 30ch; }

/* --------------------------------------------------- dark product page -- */
/* tinnox.com.au/led-video-wall/retail-space/ is the one dark page on the site:
   near-black grounds, a 60px white heading, and a grey supporting line with
   individual phrases lifted to white. That is kept — it is the best thing about
   the original, and it is the same move Apple makes on a product page.

   The measurements below are theirs, taken at a 1440 window where their content
   column runs 1130px wide from x=148. Ours already lands on that column, so the
   numbers transfer directly. They use three widths inside it, and getting those
   wrong is what made the first pass read as "close but not it":

     column  1130   headings, ledes, the closing lines, the cabinet render
     cards   1060   two 500px cards with a 60px gutter
     photo    930   the store photograph, centred

   The centred claim is not a width at all: the live page shapes it with
   explicit <br> breaks, three measured lines centred in the column, and the
   markup carries the same breaks.

   One number is not kept. Their card body is #333 on a near-black card, which
   measures about 1.4:1 — the words are there but you cannot read them. Ours use
   the same grey as the rest of the dark page, #86868b, at 5.6:1. */
.prod {
  --paper-dark: #f5f5f7;
  --grey-dark:  #86868b;
  /* Pure black, not --night. The cabinet render is cut out on #000, so any
     other black draws a visible rectangle around it instead of letting it
     float — which is the whole point of that shot. */
  background: #000; color: var(--grey-dark);
}
.prod-band { padding: clamp(56px, 7vw, 100px) 0; display: flow-root; }
/* Same-colour bands stack without doubling the air. flow-root stops a
   first-child margin from collapsing out of a zero-top-padding band and
   painting a strip of the parent black between two grey sections. */
.prod-band + .prod-band { padding-top: 0; }
/* The live page puts 120px of black under the cabinet render AND 120px of
   grey above the next heading. Collapsing the grey band's top padding
   left only the black, which is why Revolutionize sat too close to the
   image. Restore it only at the colour change. */
.prod-band:not(.prod-alt):has(+ .prod-alt) { padding-bottom: clamp(72px, 8.5vw, 120px); }
.prod-band:not(.prod-alt) + .prod-alt { padding-top: clamp(72px, 8.5vw, 120px); }
/* Their second ground, sampled: #161617. */
.prod-alt { background: #161617; }
/* Grey on grey: live's cards sit 40px above Transform, not another 100px
   band. That empty strip is the same near-black as the cards and read as a
   hole in the page. The last band keeps their 200px close instead. */
.prod-alt + .prod-alt { padding-bottom: clamp(24px, 3vw, 40px); }
.prod > .prod-alt:last-child { padding-bottom: clamp(80px, 14vw, 200px); }

/* The opener runs the live page's own hierarchy: the page NAME is the small
   line (~14px grey) and the tagline under it is the prominent one (~30px
   white) — the strip these pages open with on tinnox.com.au, kept in our type.
   The h1 stays on the name: small is a style, not a demotion. */
.prod-title {
  /* No text-wrap: balance. The live 60px headings run the full column and
     wrap where the line fills; balance was packing them onto two even
     lines at about half the width. */
  margin: 0; color: var(--paper-dark);
  font-size: clamp(30px, 4.2vw, 60px);
  font-weight: 600; letter-spacing: -.022em; line-height: 1.083;
}
.prod-lede {
  margin: clamp(16px, 2vw, 28px) 0 0;
  font-size: clamp(16px, 1.4vw, 19.2px); line-height: 1.5; letter-spacing: -.012em;
}
/* The live page puts a full 50px between each 60px heading and its line —
   the pause is part of the arrangement. Only under a title: the ledes that
   open a section on their own keep the tighter default above. */
.prod-title + .prod-lede { margin-top: clamp(20px, 3.5vw, 50px); }
.prod-title + .prod-list { margin-top: clamp(20px, 3.5vw, 50px); }
/* Colour, not weight — b is the right element for type that is set apart
   without being more important, and that is exactly what the original does. */
.prod b { color: var(--paper-dark); font-weight: inherit; }

.prod-centre { text-align: center; }
.prod-centre .prod-lede { margin-top: 0; }

/* The closing "Contact Us…" line, a step down from the lede: theirs is 16px
   regular against the lede's 19.2px semibold, and 20px below it. */
.prod-note {
  margin: 20px 0 0;
  font-size: 16px; line-height: 1.5; letter-spacing: -.012em;
}

/* The product render fills the column and floats on the black with nothing
   around it; the photograph is a framed object at 930, centred, and is the
   only thing on the page with corners. Every photograph in this frame is the
   file the live page publishes, so its own shape IS the frame's shape and
   nothing is ever cropped. */
.prod-shot { margin: clamp(34px, 4.5vw, 64px) auto 0; }
.prod-shot img { width: 100%; height: auto; }
.prod-photo {
  display: block; margin: clamp(34px, 4.5vw, 64px) auto 0;
  max-width: 930px; width: 100%; height: auto; border-radius: 30px;
}

/* Public Space (and the other kiosk product pages that share it): the first
   band is a two-column split — copy on the left, a portrait product render
   on the right — not a heading stacked over a landscape cabinet. Live sizes
   that render to 700px tall, contained, sitting on the right of its column.
   Phone is 600px and centred, which is their own mobile rule. */
.prod-hero {
  display: grid; grid-template-columns: 1fr 1fr; align-items: start;
  gap: clamp(16px, 3vw, 40px);
}
.prod-hero .prod-title { margin-top: 0; }
.prod-hero-shot { display: flex; justify-content: flex-end; min-width: 0; }
.prod-hero-shot img {
  width: auto; height: 700px; max-width: 100%; object-fit: contain;
}

.prod-cards {
  display: grid; grid-template-columns: 1fr 1fr; gap: 60px;
  max-width: 1060px; margin-inline: auto;
}
.prod-card {
  background: #000; border-radius: 25px;
  /* Theirs, including the asymmetry: the copy sits 30px from the left edge
     and 50px from the right. */
  padding: 50px 50px 50px 30px;
}
.prod-card .ico {
  display: block; width: clamp(38px, 3.5vw, 50px); height: auto;
  color: var(--paper-dark);
}
.prod-card h3 {
  margin: clamp(22px, 2.5vw, 34px) 0 10px; color: var(--paper-dark);
  font-size: clamp(21px, 2vw, 28.8px); font-weight: 600; letter-spacing: -.021em;
  line-height: 1.2;
}
.prod-card p { margin: 0; font-size: clamp(15px, 1.35vw, 17.6px); line-height: 1.5; }

/* Hire overview / expos: live uses a 1.8em white line for step titles and
   feature names — between the 60px heading and the 19.2px lede. Same size
   as the card titles, without the card. */
.prod-mid {
  margin: 0; color: var(--paper-dark);
  font-size: clamp(21px, 2vw, 28.8px); font-weight: 600;
  letter-spacing: -.021em; line-height: 1.2;
}
.prod-title + .prod-mid { margin-top: clamp(20px, 3.5vw, 50px); }
.prod-lede + .prod-mid,
.prod-list + .prod-mid { margin-top: clamp(28px, 4vw, 48px); }
.prod-mid + .prod-lede { margin-top: clamp(12px, 1.6vw, 20px); }
/* Expos stacks copy / photo / copy in one band, each in its own shell, so
   the heading is not a sibling of the image. Live's section padding is the
   gap; without it the next title sits on the frame. */
.shell:has(> .prod-photo) + .shell > .prod-mid:first-child {
  margin-top: clamp(48px, 6.5vw, 88px);
}

/* Labelled lists. Live draws a white disc with a fake absolutely-positioned
   bullet and sets the body at weight 300. We keep the disc in paper and the
   label as b, same as every other dark page. */
.prod-list {
  margin: clamp(16px, 2vw, 28px) 0 0;
  padding: 0; list-style: none;
}
.prod-list li {
  position: relative;
  margin: 0 0 15px; padding-left: 1.15em;
  font-size: clamp(16px, 1.4vw, 19.2px); line-height: 1.5; letter-spacing: -.012em;
}
.prod-list li:last-child { margin-bottom: 0; }
.prod-list li::before {
  content: "•";
  position: absolute; left: 0; color: var(--paper-dark);
}

/* --------------------------------------------------------------- cta -- */
/* Live look-display-sec: 60px padding, 2.5rem line, then the button. The old
   20ch cap wrapped "Ready to better reach your audience?" onto two lines. */
.cta {
  padding: 60px 0;
  background: var(--paper);
}
.cta-in { display: grid; justify-items: center; text-align: center; gap: 20px; }
.cta-line {
  max-width: none;
  font-size: clamp(28px, 3.2vw, 40px);
  letter-spacing: -.04em;
  overflow-wrap: normal;
  text-wrap: balance;
}

/* ------------------------------------------------- fine print + footer -- */
/* Apple's foot of page: one light-grey block holding the small print, then the
   directory of links, then the legal bar, divided by hairlines and set almost
   entirely at 12px. It reads as an appendix rather than as a second website,
   which is what a dark 14px footer had turned it into.

   The two live on separate elements only because one is content and the other
   is navigation; visually they are a single block, so neither carries a
   background of its own. */
.fine, .foot { background: var(--mist); }

.fine { padding: clamp(44px, 5vw, 68px) 0 clamp(30px, 4vw, 44px); }
.fine-label {
  margin: 0 0 18px;
  font-size: 12px; font-weight: 600; letter-spacing: -.01em;
  color: color-mix(in srgb, var(--ink) 88%, transparent);
}
/* Two columns of small print, so twelve paragraphs do not read as a wall. */
.fine-body { columns: 2; column-gap: clamp(28px, 4vw, 64px); }
.fine-body p {
  margin: 0 0 14px; break-inside: avoid;
  font-size: 12px; line-height: 1.5; letter-spacing: -.01em;
  color: color-mix(in srgb, var(--ink) 56%, transparent);
}

.foot {
  padding: 0 0 26px;
  color: color-mix(in srgb, var(--ink) 72%, transparent);
  font-size: 12px; line-height: 1.34; letter-spacing: -.01em;
}

/* Hairlines rather than gaps do the dividing, so the three parts read as one
   block with rules through it. */
.foot-grid {
  display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.4fr;
  gap: clamp(24px, 3vw, 44px);
  padding: clamp(26px, 3vw, 36px) 0;
  border-top: 1px solid var(--line-2);
}
.foot-col { min-width: 0; }
.foot-brand .mark { width: 88px; margin-bottom: 16px; }
.foot-blurb {
  margin: 0 0 18px; max-width: 40ch;
  color: color-mix(in srgb, var(--ink) 56%, transparent);
}

/* Icons rather than words, as solid ink discs with the glyph knocked out in
   paper. The outlined version read as four faint rings on a grey ground; the
   filled one is the only place in the foot of page with any weight to it,
   which is what makes a set of four read as a set. */
.social { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 22px; }
.social a {
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 50%; background: var(--ink); color: var(--paper);
  transition: background .2s var(--ease), transform .2s var(--ease);
}
.social a:hover { background: var(--ink-2); transform: translateY(-1px); }
/* The glyph runs to half the disc, which is where a knocked-out mark stops
   looking cramped and starts looking like a logo. */
.social svg { width: 17px; height: 17px; }

/* Apple's directory heading: the same 12px as its links, distinguished by
   weight and ink rather than by size, caps or tracking. */
.foot-label {
  margin: 15px 0;
  font-size: 12px; font-weight: 600;
  color: color-mix(in srgb, var(--ink) 88%, transparent);
}
.foot-col > .foot-label:first-child { margin-top: 0; }
.foot-label a { color: inherit; }

.foot-list {
  display: grid; gap: 3px; min-width: 0;
  grid-template-columns: minmax(0, 1fr);
}
.foot-list a { color: inherit; transition: color .18s var(--ease); }
.foot-list a:hover, .foot-label a:hover { color: var(--ink); text-decoration: underline; }
.foot-list a, .foot-plain li {
  line-height: 1.55;
}
.foot-plain li {
  color: color-mix(in srgb, var(--ink) 56%, transparent);
  overflow-wrap: break-word;
}
.loc {
  display: inline; white-space: nowrap;
  color: color-mix(in srgb, var(--ink) 88%, transparent); font-weight: 600;
}
.loc::after { content: ":"; }

.foot-bar {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 12px;
  padding-top: 18px; border-top: 1px solid var(--line-2);
  color: color-mix(in srgb, var(--ink) 56%, transparent);
}
.foot-bar p { margin: 0; }
.foot-legal { display: flex; flex-wrap: wrap; gap: 18px; }

/* --------------------------------------------------------------- flag -- */
/* The way back to the hub, on every prototype. */
.flag {
  position: fixed; right: 14px; bottom: 14px; z-index: 90;
  background: var(--ink); color: var(--paper);
  font-family: var(--mono); font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; padding: 8px 12px; border-radius: 999px;
  opacity: .8; transition: opacity .2s var(--ease);
}
.flag:hover { opacity: 1; }

/* ================================================== responsive ======== */

/* Tablet — the nav still fits, the grids do not. */
/* The drawer, and the scroll lock that comes with it, exist only below the
   breakpoint. Scoping both here rather than leaving them to JavaScript is what
   makes widening the window safe: a page that grows past 768px releases the
   lock and drops the panel by itself, with no resize event needing to arrive
   on time. site.js still tidies the aria state on resize. */
@media (min-width: 768px) {
  .drawer { display: none; }
}
/* The nav drawer only exists below the breakpoint, but the lightbox opens at any
   width, and both use this class to stop the page scrolling underneath. */
body.drawer-open { overflow: hidden; }

@media (max-width: 1079px) {
  .gallery { grid-template-columns: repeat(4, 1fr); }
  .logos { grid-template-columns: repeat(4, 1fr); }
  .nav-links { gap: 20px; font-size: 14px; }
  .foot-grid {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "brand about"
      "industries places";
    row-gap: 44px;
  }
  .foot-brand { grid-area: brand; }
  .foot-about { grid-area: about; }
  .foot-industries { grid-area: industries; }
  .foot-places { grid-area: places; }
}

/* Phone — the nav collapses into the drawer and every row goes vertical. */
@media (max-width: 767px) {
  .nav-links, .nav-quote, .fly, .fly-frame, .nav-veil { display: none !important; }
  .burger { display: flex; }

  /* The paired tiles stack, and keep the same white line between them. */
  .tile-row { grid-template-columns: 1fr; }

  /* A narrow tile is a tall column of copy — it runs to about two thirds of
     the tile rather than half — so it gets a little more height to work in.
     Portrait shapes, again measured off the reference phone (375x812). Losing
     vh here fixes a real iOS Safari bug as well: its toolbar collapses as you
     scroll, so vh changed mid-scroll and every tile quietly resized under the
     reader. The paired row is one column at this width, so it resets to the
     full-width shape. */
  .tile-photo,
  .tile-row .tile-photo { aspect-ratio: 365 / 406; }
  .tiles-projects {
    grid-template-columns: 1fr;
    max-width: 420px;
  }
  .tiles-projects.tiles-compact .tile-photo { aspect-ratio: 1 / 1; }

  /* Same reason the compact gradient has to reach further here: stacked buttons
     push the copy from 36% of the tile down to about 52%. */
  .tiles-compact .tile-photo::before {
    background: linear-gradient(180deg,
      rgb(8 10 14 / calc(var(--scrim) * 1.04)) 0%,
      rgb(8 10 14 / var(--scrim)) 52%,
      rgb(8 10 14 / 0) 74%);
  }

  .tiles-tall .tile-photo,
  .tile-photo.is-xtall { aspect-ratio: 365 / 406; }
  .tiles-tall .tile-photo::before {
    background: linear-gradient(180deg,
      rgb(8 10 14 / calc(var(--scrim) * 1.04)) 0%,
      rgb(8 10 14 / var(--scrim)) 46%,
      rgb(8 10 14 / 0) 68%);
  }

  .logos { grid-template-columns: repeat(3, 1fr); }
  .cards { grid-template-columns: 1fr; }
  .card-shot { aspect-ratio: 16 / 9; }

  /* The peek narrows to a hint, and the arrows come off the neighbours and
     back onto the slide — there is no longer room beside it. What a phone
     actually drives this with is the swipe, which site.js adds. */
  .reel { --slide-w: 84vw; }
  .slide { border-radius: 10px; }
  .reel-arrow { width: 40px; height: 40px; }
  .reel-prev { left: 12px; }
  .reel-next { right: 12px; }
  .play-tri { width: 52px; }

  /* A 7px dot is the right size to look at and the wrong size to hit, so the
     button grows around it rather than the dot growing. */
  .reel-dots { padding: 3px 8px; }
  .reel-dots button { height: 44px; }

  .qa-a { padding-left: 0; }

  /* The editorial block goes to one column — a 28px heading and its paragraph
     cannot share 375px — and the paired squares stack, because side by side
     they land at about 165px each, too small to read a sign in. */
  .prod-cards { grid-template-columns: 1fr; gap: 16px; }
  .prod-card { padding: 32px 26px; }

  .prod-hero { grid-template-columns: 1fr; }
  .prod-hero-shot { justify-content: center; }
  .prod-hero-shot img { height: 600px; }

  /* The centred claim's line breaks are measured for the desktop column; on a
     phone the text rewraps anyway, and a forced break mid-wrap leaves a snag. */
  .prod-centre br { display: none; }

  .ed-head { grid-template-columns: 1fr; gap: 10px; }
  /* Flush right only works while it is a margin note beside something. Once
     it is stacked under the heading it is just a line of text. */
  .ed-lede { text-align: left; padding-top: 0; }
  .ed-shots-2 { grid-template-columns: 1fr; }
  .iso-card { grid-template-columns: 1fr; }
  .iso-copy { padding: clamp(28px, 7vw, 40px); }
  .war-series { grid-template-columns: 1fr; }
  .war-pair { grid-template-columns: 1fr; }
  .legal-pair { grid-template-columns: 1fr; }
  .war-table thead { display: none; }
  .war-table tr { display: block; margin: 0 0 12px; }
  .war-table th, .war-table td {
    display: block; width: 100%;
    border-bottom: 0;
  }
  .war-table td { border-top: 0; }
  .war-table tr > :last-child { border-bottom: 1px solid var(--line); }
  .fine-body { columns: 1; }

  .gallery { grid-template-columns: repeat(2, 1fr); }
  /* Stacked controls: at phone width there is no room beside the picture. */
  .lightbox { grid-template-columns: 1fr 1fr; justify-items: center; align-content: center; }
  .lightbox .lb-stage { grid-row: 1; grid-column: 1 / -1; }
  .lightbox .lb-prev { grid-column: 1; justify-self: end; }
  .lightbox .lb-next { grid-column: 2; justify-self: start; }
  .lb-stage img { max-height: calc(100dvh - 220px); }

  /* Keep breadcrumb links comfortable to tap. */
  .crumb { min-height: 44px; }
  .crumb a { display: inline-flex; align-items: center; min-height: 44px; }
  .social a { width: 44px; height: 44px; }
  /* Directory lists follow tinnox.com.au: 15px under a heading, 3px between
     rows. 44px hits stay on the legal bar and social discs, not on every
     footer word — those hits made linked titles and About/Explore items
     much looser than Locations. */
  .foot-list { gap: 3px; }
  .foot-list a { display: block; min-height: 0; }
  .foot-plain li { padding: 0; }
  .foot-label { margin: 15px 0; }
  .foot-label a { display: inline; min-height: 0; }

  .flag { min-height: 40px; display: inline-flex; align-items: center; }
  .foot-bar { flex-direction: column; align-items: flex-start; }
  .foot-legal a { display: flex; align-items: center; min-height: 44px; }
}

/* Small phone — nothing may need two hands. */
@media (max-width: 419px) {
  .gallery { grid-template-columns: repeat(2, 1fr); }
  .tile-acts { flex-direction: column; align-items: stretch; width: 100%; max-width: 300px; }
  .logos { grid-template-columns: repeat(2, 1fr); }
  .social { gap: 6px; }
  .social a { padding: 0 10px; font-size: 12px; }
  .qstep { font-size: 12px; padding: 0; }
}

/* --------------------------------------------------- motion / print -- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .card:hover .card-shot img { transform: none; }
  .fly a {
    animation: none !important; opacity: 1; transform: none;
  }
  .nav-item:not([data-open]) .fly a { opacity: 0; }
}

@media print {
  .nav, .nav-veil, .drawer, .flag, .reel-arrow, .reel-dots, .play { display: none !important; }
  .tile { break-inside: avoid; }
}
