/* ==========================================================================
   Tech4TIME — pages/company-profile.css
   Section order follows the CURRENT LIVE SITE: milestones, then background
   (experience, clients, journey), then professional excellence (technology,
   principles). The NextJS build runs almost the reverse order.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Milestones
   THE TIMELINE ITSELF IS NOT HERE. Its rules are
   assets/css/pages/milestones.css, because /pages/milestones/ draws the same
   timeline and a second copy is a second thing to keep true. This page loads
   both stylesheets; see its seo_head() call.

   What IS here is the one thing that belongs to this page and not to that one:
   the link out to the full history, which only exists where a window is being
   shown.
   -------------------------------------------------------------------------- */

.milestones__more {
  margin-block-start: var(--space-lg);
  text-align: center;
}

/* --------------------------------------------------------------------------
   2. Background: experience, clients, journey
   -------------------------------------------------------------------------- */

.background__block + .background__block,
.excellence__block + .excellence__block {
  margin-block-start: var(--space-2xl);
}

.background__title {
  margin-block-end: var(--space-md);
  font-size: var(--text-xl);
  text-align: center;
}

.background__lead {
  margin-block-start: calc(var(--space-md) * -1 + var(--space-2xs));
  margin-block-end: var(--space-lg);
  font-size: var(--text-sm);
  text-align: center;
  color: var(--text-secondary);
}

.stats {
  display: grid;
  gap: var(--space-md);
  grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
}

.stat {
  padding: var(--space-lg);
  text-align: center;
  background-color: var(--bg-elevated);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

.stat__figure {
  font-size: var(--text-3xl);
  font-weight: 800;
  line-height: 1;
  background-image: var(--silver-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.stat__label {
  margin-block-start: var(--space-2xs);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--text-secondary);
}

/* COUNTED COLUMNS, NOT auto-fit, and the difference is the whole point.
   auto-fit decides the column count from the track MINIMUM, so one number has
   to serve every screen — and minmax(min(10rem, 100%), 1fr) served a 360px
   phone ONE column, which is why nine logos were 1,136px tall there and fifty
   would have been eight screens of them. Three tiers say three things.

   TWO ON A PHONE AND NOT THREE, WHICH IS A MEASURED DECISION. A client mark is
   somebody else's wordmark, and three across a 360px screen draws it in a 95px
   tile against the 145-176px it gets on every larger screen — half the size,
   on the screen where it is hardest to read. Two keeps the tile near 160px at
   360px and near 190px at 414px, which is the same mark at the same size all
   the way up. The accreditation badges on the about page made the same call
   for the same reason.

   THE COLUMN COUNTS AND COMPANY_CLIENTS_WALL ARE ONE DESIGN. Twelve divides by
   2, 4 and 6, so the wall above the expander is always whole rows — six, then
   three, then two. Change a tier here and the cap has to divide into it, or
   the last row before the button comes out ragged. */
.clients {
  display: grid;
  gap: var(--space-sm);
  grid-template-columns: repeat(2, 1fr);
  padding: 0;
  margin: 0;
  list-style: none;
}

@media (min-width: 48em) {
  .clients {
    grid-template-columns: repeat(4, 1fr);
  }
}

@media (min-width: 64em) {
  .clients {
    grid-template-columns: repeat(6, 1fr);
  }
}

/* The plate is --artwork-plate, not --bg-elevated. Several of these marks are
   dark ink on transparency (Aitken Spence, MGC, CDBL are close to solid
   black), so on the dark theme's elevated surface they did not merely look
   wrong — they vanished into it at about 1.4:1. */
.client-card {
  display: grid;
  place-items: center;
  min-height: 7rem;
  padding: var(--space-md);
  background-color: var(--artwork-plate);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius);
  transition:
    border-color var(--duration) var(--ease-out),
    transform var(--duration) var(--ease-out);
}

.client-card:hover {
  transform: translateY(-3px);
  border-color: var(--silver-accent-mid);
}

/* Client marks are supplied in their own colours. Rather than force them to
   greyscale, which would misrepresent someone else's brand, they sit on the
   artwork plate so they read correctly in both themes. */
.client-card__logo {
  width: auto;
  max-width: 100%;
  max-height: 3.5rem;
  object-fit: contain;
}

/* The photographs are a slideshow, and deliberately not a full-width one. Run
   to the width of the band a single picture would be three times the size it
   was in the row, which is not what was asked for — the frame stays as it was
   and the slider is centred inside the band. One number to change if it should
   ever fill the width instead.

   --slider-columns is the layout it falls back to without JavaScript: the row
   it has always been. */
.journey__slider {
  --slider-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
  max-width: 30rem;
  margin-inline: auto;
}

.journey__item {
  overflow: hidden;
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

.journey__image {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform var(--duration-slow) var(--ease-out);
}

.journey__item:hover .journey__image {
  transform: scale(1.04);
}

/* --------------------------------------------------------------------------
   2b. The expander under a wall of logos
   Shared by the clients wall and, below 768px, the technology grid: the first
   COMPANY_*_WALL of them show, and the rest are in a closed <details>.

   <details> and <summary>, which the browser already implements — so it opens
   with no JavaScript, is reachable by keyboard without a roving tabindex, and
   is announced correctly without an aria- attribute. Same call, and the same
   reasoning, as the certifications page.

   THE TAIL IS A SECOND GRID WITH THE SAME COLUMNS, so the two read as one
   continuous wall. That only holds because the first grid is always full — see
   the note on .clients above.
   -------------------------------------------------------------------------- */

.wall-more {
  margin-block-start: var(--space-sm);
}

/* THE SUMMARY IS AS WIDE AS ITS LABEL, and that is a focus decision rather
   than a visual one. base.css draws the focus ring for a <summary> as a
   box-shadow, because Firefox will not give one an outline at all — and a
   shadow follows the element's own box. A full-width summary would therefore
   ring the whole row while only the pill inside it looks pressable. Sized to
   its content, the ring lands exactly on the thing that reads as a button, and
   this file needs no focus rule of its own.

   list-style AND the -webkit- pseudo-element, not one of them: Blink and older
   WebKit expose the disclosure triangle as ::-webkit-details-marker, Gecko and
   current WebKit render it as the summary's own list marker. Removing only one
   leaves the triangle showing in the other.

   It reads as a control, so it is drawn as one — but it is a <summary> and not
   a <button>, so the button's rules cannot simply be borrowed. */
.wall-more__summary {
  width: fit-content;
  margin-inline: auto;
  padding: var(--space-2xs) var(--space-md);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-secondary);
  list-style: none;
  cursor: pointer;
  background-color: var(--bg-elevated);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-full);
  transition:
    border-color var(--duration) var(--ease-out),
    color var(--duration) var(--ease-out);
}

.wall-more__summary::-webkit-details-marker {
  display: none;
}

.wall-more__summary:hover {
  color: var(--text-primary);
  border-color: var(--silver-accent-mid);
}

/* One of the two labels at a time. See the note in the page's markup. */
.wall-more__open {
  display: none;
}

.wall-more[open] .wall-more__shut {
  display: none;
}

.wall-more[open] .wall-more__open {
  display: inline-block;
}

/* A CLOSED <details> DOES NOT HIDE THIS TAIL, AND IT NEVER HAS
   A browser hides the content of a closed <details> with a UA rule on that
   content. An author rule beats a UA rule, and .wall-more__rest is also
   .clients or .tech-sphere__list, both of which declare display: grid -- so
   the tail has been laid out and painted the whole time, in EVERY browser.
   Measured on the company profile at 390px: closed, the tail was 1311px tall
   in Firefox and 1355px in Chrome, with an offsetParent, 32 children and
   visibility: visible.

   So pressing the control only ever swapped its own label. Nothing collapsed
   and nothing expanded, which is why it was reported as a button that "stays
   in the same position" -- it was sitting in a grid that was always open.

   This is the rule the UA stylesheet meant to apply, written where it wins.
   Note that tools/apply_reveals.py:55 reasons from "a closed <details> has no
   layout box" and that premise was false here; the conclusion it drew -- keep
   data-reveal out of the tail -- is still right, so nothing there changes. */
.wall-more:not([open]) .wall-more__rest {
  display: none;
}

/* THE CONTROL BELONGS BELOW WHAT IT COLLAPSES, AND <details> PUTS IT ABOVE
   A <summary> always renders before its content -- that is the element, not a
   choice. Closed, that is right: the button sits at the end of the wall. Open,
   it left "Show fewer" marooned above nine more rows of logos, which is a
   control you have to hunt for. It was reported from a phone, where this is
   the only place the control appears at all: the sphere is off at that width,
   and .tech-sphere--on hides it everywhere else.

   So the order is reversed visually, in CSS, with the markup untouched -- the
   <details> keeps working with JavaScript off.

   ONLY WHILE OPEN. Scoped this way the element stays display: block whenever
   the tail is meant to be hidden, so the rule above is the only thing deciding
   that, and no browser's <details> handling has to cope with a flex container
   it did not expect. order has nothing to do on a tail that is not rendered.

   Nothing in the tail is focusable -- it is <li> of pictures and
   visually-hidden names, measured at zero links, buttons and tabindex -- so
   reordering it visually does not put the focus ring out of step with the
   page. check_focus.py is what keeps that true. */
.wall-more[open] {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}

.wall-more[open] .wall-more__rest {
  order: 1;
  /* The gap above is the flex gap now, and a margin as well would double it. */
  margin-block-start: 0;
}

.wall-more[open] .wall-more__summary {
  order: 2;
}

/* --------------------------------------------------------------------------
   3. Technology sphere
   Ships as a plain grid. tech-sphere.js adds --on, which is what switches it
   into the 3D arrangement; without scripting, or under prefers-reduced-motion,
   the grid is what stays.
   -------------------------------------------------------------------------- */

/* COUNTED COLUMNS, for the reason .clients gives — and its OWN counts, for a
   reason .clients does not have. The face is aspect-ratio 1, so a plate is
   exactly as wide as its column: four across a tablet would draw a 160px
   circle where the design wants about a hundred. Three, then six, then nine
   holds the plate near that size at every width, and COMPANY_TECHNOLOGY_WALL
   is eighteen because eighteen divides into all three. */
.tech-sphere__list {
  display: grid;
  gap: var(--space-sm);
  grid-template-columns: repeat(3, 1fr);
  padding: 0;
  margin: 0;
  list-style: none;
}

@media (min-width: 48em) {
  .tech-sphere__list {
    grid-template-columns: repeat(6, 1fr);
  }
}

@media (min-width: 64em) {
  .tech-sphere__list {
    grid-template-columns: repeat(9, 1fr);
  }
}

.tech-sphere__face {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  padding: var(--space-sm);
  background-color: var(--artwork-plate);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: 50%;
}

/* Product marks are other companies' brands, so they keep their own colours;
   the white disc is what makes them legible against either theme. */
.tech-sphere__logo {
  width: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* --- the 3D arrangement, once the script has taken over ------------------ */

/* The expander is what the cap is FOR, and the sphere is what the cap is not
   for. When the script turns the sphere on it moves every plate out of the
   <details> and into the list above, so there is nothing left in there to
   open — and a control that opens onto nothing is worse than no control. */
.tech-sphere--on .tech-sphere__more {
  display: none;
}

.tech-sphere--on {
  /* How far back a plate fades as it turns away from the viewer. The far side
     is ALREADY drawn smaller than the near side -- 47.8px against 67.5px --
     and this is the same depth cue said a second way, so that a plate behind
     another reads as behind it rather than as a blob poking out from the edge
     of it. One number, here, rather than a literal down in the rule. */
  --sphere-back: 0.35;

  /* --sphere-size and --sphere-radius are measured and set by the script. */
  height: var(--sphere-size, 32rem);

  /* PERSPECTIVE MOVES WITH THE SPHERE, and it has to. It was a fixed 1200px
     against a fixed 560px sphere; now the sphere is sized to the room it has,
     and a fixed perspective over a growing radius magnifies the near face and
     shrinks the far one -- measured, the near plate went 67.5px to 74.5px as
     the sphere grew from 560 to 814. That would make growing the sphere a way
     of changing the plate's size, which is the one thing this must not do.

     1200/560 is exactly 15/7. Holding perspective/size constant holds
     perspective/radius constant, so the projection is identical at every size
     and the plate measures 67.4px whether the sphere is 560 or 1136 across.
     Read from --sphere-size rather than set separately, so the two cannot
     drift apart. */
  perspective: calc(var(--sphere-size, 32rem) * 15 / 7);
  /* Horizontal drags turn the sphere; vertical ones are left to the page, so a
     visitor who starts a scroll on top of the logos still scrolls. */
  touch-action: pan-y;
  /* It can be taken hold of and turned — say so. */
  cursor: grab;
  /* A drag across the logos would otherwise select their alt text, and the
     selection would follow the pointer instead of the sphere. */
  user-select: none;
  -webkit-user-select: none;
}

.tech-sphere--held {
  cursor: grabbing;
}

.tech-sphere--on .tech-sphere__list {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  /* --rot-x/--rot-y, and their four sines and cosines, are written once per
     frame on this element; the items below read all six through inheritance,
     so a frame is six property writes rather than one per logo. The four
     trigonometric ones are what lets each item work out its own depth without
     the script touching it -- see --depth below. */
  transform: rotateX(var(--rot-x, 0deg)) rotateY(var(--rot-y, 0deg));
}

/* Laid out at twice the size it is shown at, then scaled back down.

   Inside a preserve-3d subtree the browser rasterises each tile once and reuses
   that texture as perspective scales it toward and away from the viewer, so a
   tile rasterised at its display size goes soft the moment it comes forward.
   Rasterising at 2x and scaling down gives it the pixels to stay sharp. The
   scale is last in the list, so it acts on the tile alone and leaves the
   translate3d that positions it on the sphere untouched. */
.tech-sphere--on .tech-sphere__item {
  --tile: 7rem;
  --shown: 0.5;

  /* WHERE THIS PLATE IS FACING, AFTER THE SPHERE HAS BEEN TURNED: −1 at the
     back, +1 at the front. The list is rotated rotateX(x) rotateY(y), so a
     direction (ux, uy, uz) ends up with a depth of

         uy·sin(x) + (uz·cos(y) − ux·sin(y))·cos(x)

     and that is this expression, exactly. The four trigonometric terms are
     inherited from the list, where the script writes them once a frame,
     because they are the same for every plate; the three direction components
     are the plate's own and never change. So the browser finishes the sum per
     plate as part of the style recalculation it is already doing for the
     transform, and no script ever touches a logo.

     No sin() or cos() here on purpose. Unitless var() inside calc() works
     everywhere; CSS trigonometry does not, and the fallbacks below would then
     be doing real work rather than describing the untilted state. */
  --depth: calc(var(--uy, 0) * var(--sin-x, 0)
              + (var(--uz, 1) * var(--cos-y, 1) - var(--ux, 0) * var(--sin-y, 0))
                * var(--cos-x, 1));

  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--tile);
  height: var(--tile);
  margin: calc(var(--tile) / -2);
  transform-style: preserve-3d;

  /* Full strength at the front, --sphere-back at the back, and every plate is
     at both within one turn -- nothing is permanently dim. The plates are a
     fixed size and stay one; this is the only thing about them that changes
     with where they are. */
  opacity: calc(var(--sphere-back, 0.35)
              + (1 - var(--sphere-back, 0.35)) * (var(--depth) + 1) / 2);

  /* Out to its point on the sphere -- a DIRECTION times a radius, so growing
     the sphere is one property on the parent rather than three per logo --
     then the parent's rotation undone in reverse order so the logo keeps
     facing the viewer instead of turning edge-on as it orbits. */
  transform:
    translate3d(calc(var(--ux, 0) * var(--sphere-radius, 0px)),
                calc(var(--uy, 0) * var(--sphere-radius, 0px)),
                calc(var(--uz, 0) * var(--sphere-radius, 0px)))
    rotateY(calc(-1 * var(--rot-y, 0deg)))
    rotateX(calc(-1 * var(--rot-x, 0deg)))
    scale(var(--shown));
}

/* Anything a reader reaches for comes up to full strength, wherever it is on
   the sphere. The face scales under it; this is the plate around it. */
.tech-sphere--on .tech-sphere__item:hover {
  opacity: 1;
}

.tech-sphere--on .tech-sphere__face {
  width: 100%;
  height: 100%;
  padding: 1rem;
  /* Everything here is halved by the scale above, so the hairline is specified
     at 2px to land on one. */
  border-width: 2px;
  box-shadow: var(--shadow-sm);
  transition: transform var(--duration) var(--ease-out);
}

.tech-sphere--on .tech-sphere__item:hover .tech-sphere__face {
  transform: scale(1.18);
}

/* --------------------------------------------------------------------------
   4. Principles
   -------------------------------------------------------------------------- */

.values {
  display: grid;
  gap: var(--space-md);
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}

.value-card {
  padding: var(--space-lg);
  text-align: center;
  background-color: var(--bg-elevated);
  border: var(--border-width) solid var(--border-subtle);
  border-radius: var(--radius-lg);
  transition:
    transform var(--duration) var(--ease-out),
    border-color var(--duration) var(--ease-out),
    box-shadow var(--duration) var(--ease-out);
}

.value-card:hover {
  transform: translateY(-4px);
  border-color: var(--silver-accent-mid);
  box-shadow: var(--shadow);
}

.value-card__icon {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  margin-inline: auto;
  margin-block-end: var(--space-sm);
  font-size: 1.5rem;
  color: var(--on-accent);
  background-image: var(--silver-gradient-fill);
  border-radius: 50%;
}

.value-card__title {
  margin-block-end: var(--space-3xs);
  font-size: var(--text-lg);
}

.value-card__text {
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  color: var(--text-secondary);
}
