/* volocal-brand.css — the whole brand animation, colour taken from the text it
   stands in. Every rule here is the shipped one from src/css/01-base.css and
   src/css/02-library.css, with the application's palette tokens replaced by
   `currentColor` so both themes work with no extra code. */

/* ================================================================ wordmark */

/* The host is the hover target. 10/12 of padding with the same negative margin
   is the prototype's enlarged hit area: closed, the mark is under 40 px wide,
   which is little to aim at, and the negative margin keeps it out of layout. */
.volocal-brand {
  display: inline-flex;
  align-items: center;
  /* `.header-brand-mark` in src/css/01-base.css. The prototype's roomier
     10/12 hit area with a matching negative margin is not what ships. */
  padding: 4px 2px;
}

/* 82 × 25 is the drawing's own viewBox at 1:1. The geometry of the closed state
   is not repeated here — `--wordmark-closed`, `--wordmark-shift` and
   `--wordmark-tm` arrive from the script, which is where the outlines are, so a
   redrawn letterform cannot leave this file saying something else.

   2 px down: the ™ lifts the top of the drawing's box and the smile under the
   `o` drops its bottom, so a box centred in a bar does not put the letters where
   the eye expects them. The letters run y 0.08 to 16.52 in a 25 tall box — their
   weight sits above the middle, and the mark reads as flying upward.

   `position`/`top`, not `transform: translateY`. The offset is the same, but a
   transform on this box makes it a compositing layer and hands everything inside
   it to the rasteriser; `top` moves it in layout and leaves the drawing a
   drawing. */
.wordmark {
  display: block;
  overflow: hidden;
  width: calc(82px * var(--wordmark-unit, 1));
  height: calc(25px * var(--wordmark-unit, 1));
  position: relative;
  top: calc(2px * var(--wordmark-unit, 1));
  transition: width var(--wordmark-collapse) var(--wordmark-ease);
}
/* Fixed, not `100%`: the span closes around the drawing and clips it. A svg
   that shrank with the box would squash the letters instead of cropping them. */
.wordmark-svg {
  display: block;
  width: calc(82px * var(--wordmark-unit, 1));
  height: calc(25px * var(--wordmark-unit, 1));
  flex: 0 0 auto;
}
.wordmark-svg path { fill: currentColor; }
.wordmark-shift,
.wordmark-v,
.wordmark-cal,
.wordmark-tm {
  transition: transform var(--wordmark-collapse) var(--wordmark-ease),
              opacity var(--wordmark-collapse) var(--wordmark-ease);
}

/* The transforms are in SVG user units, which stay 1:1 with the viewBox at any
   `--wordmark-unit`; only the box's own width is in CSS pixels and has to scale. */
.wordmark.closed { width: calc(var(--wordmark-closed) * var(--wordmark-unit, 1) * 1px); }
.wordmark.closed .wordmark-shift { transform: translateX(calc(var(--wordmark-shift) * 1px)); }
.wordmark.closed .wordmark-tm { transform: translateX(calc(var(--wordmark-tm) * 1px)); }
/* Variant B — the outer letters leave the frame instead of going out on the
   spot. Nothing fades: `v` drives off to the left and `cal` to the right, and
   the box clips them because it closes at the same time. `cal` also carries the
   group's own −12.45, so its 44 is 31.5 of actual travel.

   Variant A stood here and is two lines: `opacity: 0` with a 7 unit drift on
   each. It is the quieter of the two, and this is the one that reads as
   machinery. Variant C, the two-beat version, was tuned in the prototype and
   never shipped. */
.wordmark.closed .wordmark-v { transform: translateX(-16px); }
.wordmark.closed .wordmark-cal { transform: translateX(44px); }

/* Under the pointer it opens again, and quicker than it closed: the closing is
   staged and this is an answer to a hand. `:focus-visible` beside `:hover`,
   because an affordance only a pointer can reach would leave every keyboard
   reader with a name they never see — give the host a `tabindex` if it is a
   control. `.ready` is what keeps a hand that happens to be resting here at
   start from cancelling the intro. */
.wordmark.ready,
.wordmark.ready :is(.wordmark-shift, .wordmark-v, .wordmark-cal, .wordmark-tm) {
  transition-duration: var(--wordmark-hover);
}
.volocal-brand:is(:hover, :focus-visible) .wordmark.ready {
  width: calc(82px * var(--wordmark-unit, 1));
}
.volocal-brand:is(:hover, :focus-visible)
  .wordmark.ready :is(.wordmark-shift, .wordmark-tm, .wordmark-v, .wordmark-cal) {
  transform: none;
  opacity: 1;
}

/* Reduced motion. The script puts `.still` on and starts the mark closed, so
   there is nothing to switch off but the transitions themselves — including the
   hover, which then answers instantly rather than not at all. */
.wordmark.still,
.wordmark.still * { transition: none !important; }

/* ==================================================== the mark: face and mill
   One element, three states. The face writes itself and then lives; the mill is
   the same four shapes seen from another side. */

.olo-face { display: block; }
.olo-face-svg {
  display: block;
  height: var(--olo-height, 63px);
  width: auto;
}
/* The outline is the pen's target. In the application it takes the pale line
   colour, which does not exist here — `currentColor` at 0.18 is the nearest
   thing that still works in both themes and against any ink. */
.olo-face-guide path { fill: currentColor; opacity: 0.18; }
.olo-face-ink path { fill: currentColor; }

/* A flat front, not a round one. A round cap is a disc of half the stroke's
   width, and on a ring whose centreline is 4.35 across that disc reaches parts
   of the letter the pen has not got to yet — black appears where the pen is not.
   A flat front advances as a clean radial cut and may be wider than the shape,
   because the letterform clips whatever spills.

   `100 200` and a resting offset of 101, not `100` and `100`: the browser
   rescales the real curve onto the hundred units `pathLength` declares, and at
   exactly 100 the resting state sits on the boundary between the drawn and
   undrawn halves of the pattern. Rounding then leaves a sliver at the start of
   each stroke — on a six-unit-wide pen, a visible tick on the outline before
   anything has begun. One unit of slack puts the rest inside the undrawn part.
   It costs 1 % of a stroke's time drawing nothing.

   White, because this is the inside of a mask: what advances is the reveal of
   the shapes, not a stroke pretending to be them. It is never seen as a colour. */
.olo-pen {
  fill: none;
  stroke: #fff;
  stroke-linecap: butt;
  stroke-linejoin: round;
  stroke-dasharray: 100 200;
  stroke-dashoffset: 101;
  transition-property: stroke-dashoffset;
  transition-timing-function: var(--olo-ease);
  transition-duration: calc(var(--olo-writing) * var(--pen-duration));
  transition-delay: calc(var(--olo-writing) * var(--pen-start));
}
.olo-pen-1, .olo-pen-3 { stroke-width: 6; }
.olo-pen-2, .olo-pen-4 { stroke-width: 5; }
.olo-face.drawn .olo-pen { stroke-dashoffset: 0; }
.olo-face.still .olo-pen { transition: none; }

/* The face blinks: the whole `o` squashed to a slit, not just the counter
   inside it. The quieter version was built — outline standing, only the counters
   closing, done with a mask so the holes stayed transparent — and rejected at
   the screen in favour of this one.

   `transform-box: fill-box` is what makes it work at all. Without it
   `transform-origin: center` is measured from the viewBox, so both eyes squash
   toward a single point between them instead of each closing where it stands.

   `.08` rather than 0: a closed eye leaves a slit. Zero turns the `o` into a
   solid dot, which reads as a full stop rather than a blink. */
.olo-eye {
  transform-box: fill-box;
  transform-origin: center;
  transition: transform var(--olo-blink) cubic-bezier(.4, 0, .6, 1);
}
.olo-face.blinking .olo-eye { transform: scaleY(.08); }
.olo-face.still .olo-eye { transition: none; transform: none; }

/* While work runs the mark turns on its side and stops being a face: the two
   `o` are rollers and the stem is sheet metal passing between them. Nothing is
   drawn for it — the same four shapes from another side.

   `scale(.84)` is what keeps the rollers inside the frame, and the first attempt
   at it was wrong. 26.2 / 30.41 — the frame's height over the drawing's length —
   assumes the drawing is centred in the frame, and it is not: the turn is about
   (27.655, 12.13) while the frame runs −1 to 25.2, leaving 13.13 above and
   13.07 below. Against a reach of 15.206 that allows 0.8595, and .861 ran past
   it by 0.022 of a unit — and it showed: at the extreme of a circle the outline
   is tangent to the frame, so a sliver of overrun takes a wide flat bite out of
   the curve. .84 leaves 0.3 of a unit.

   The prototype had no scale at all, because it drew the mill in a square
   34 × 34 frame where the turned mark fits unshrunk. The application's frame is
   26.2 tall, so here the component wins and the scale stays. */
.olo-rot {
  transform-origin: 27.655px 12.13px;
  transition: transform var(--olo-turn) cubic-bezier(.65, 0, .35, 1);
}
.olo-face.working .olo-rot { transform: rotate(90deg) scale(.84); }

/* The sheet travels along y in unturned coordinates, and it is the parent's
   rotation that makes the journey horizontal. Along x it would run lengthwise
   through the rollers rather than between them. */
@keyframes olo-pass {
  from { transform: translateY(26px); }
  to { transform: translateY(-26px); }
}
.olo-face.working .olo-sheet {
  animation: olo-pass var(--olo-pass) linear infinite;
  animation-delay: calc(var(--olo-turn) * var(--olo-lead));
}

/* The smile turns about the centre of its own arc — (27.66, 13.81), radius
   8.81 — so it slides along the curve it is itself made of rather than moving in
   a straight line. It cannot leave by turning alone, being always the same
   distance from that centre, so the turn carries the movement and the fade
   carries the departure.

   The delay sits on the resting rule rather than on `.working`, so it applies
   only to the return: the smile leaves at once and comes back after the mark has
   turned upright. The machine becomes a face again, and the smile arrives last. */
.olo-smile {
  transform-origin: 27.66px 13.81px;
  transition: opacity calc(var(--olo-turn) * .7) ease,
              transform calc(var(--olo-turn) * .9) cubic-bezier(.34, 1.25, .64, 1);
  transition-delay: var(--olo-turn);
}
.olo-face.working .olo-smile {
  transition-delay: 0ms;
  opacity: 0;
  transform: rotate(var(--olo-smile-turn));
}
/* Reduced motion keeps the face a face. Not a slower mill: none. */
.olo-face.still .olo-rot,
.olo-face.still .olo-smile { transition: none; transform: none; }
.olo-face.still .olo-sheet { animation: none; }
