/* ==========================================================================
   vivaocean-theme / tokens
   --------------------------------------------------------------------------
   This file is the single source of truth. Every literal value in the theme
   is declared here and nowhere else: there is not one color literal in any
   other file in the repository, which is grepped rather than claimed. The
   Tailwind adapters next to it (theme.css for v4, preset.js for v3) hold no
   values of their own; they point at these custom properties with var().

   The sentence used to say "exactly once", and the negative-claim audit
   caught it: #ffffff is declared twice, as --vo-accent-ink and as
   --vo-destructive-ink. That is not a duplicate to be collapsed. They are
   two independent decisions about what colour text sits on two different
   fills, and they currently agree; pointing one at the other would couple
   them, so that moving the accent's ink would silently move the
   destructive's. Two names, one value, on purpose. The claim is the one
   above instead, which is both true and the one worth making.

   Each group is annotated with the creative-direction axis the choice
   serves. The four axes are tone register, aesthetic philosophy, audience
   relationship, and sensory ambition. Read them at
   https://rampstack.co/framework/creative-direction

   This theme is a shell, and its ground is alive. Two token groups exist
   here that a register theme would not have: THE WATER, which scene.css
   composes into a seascape, and SHELL GEOMETRY, the measurements of the
   window and its rails. Both are ordinary tokens, which is what keeps a
   re-skin of the ocean a one-file edit.

   HOW CONTRAST WORKS ON THIS THEME, because it is not the usual arrangement.
   There are two worlds here with opposite polarity. Inside the window are
   light surfaces carrying dark ink. Outside it is deep water carrying light
   ink. Class decision 20 (a dark shell ground makes desk ink its own token)
   applies in full: --vo-ink and --vo-ground-ink are separate tokens and are
   not interchangeable, and the one that breaks a re-skin is the second one.

   Every ratio in the comments below is a measured WCAG 2.1
   relative-luminance figure, not an estimate. Text-over-water figures are
   quoted against THE LIGHTEST PAINT THE SCENE CAN PRODUCE, which is a light
   ray falling across deep water and resolves to #2e7095. That single number
   is what makes contrast over an animated ground provable rather than
   hopeful: the water moves, but it can never get lighter than that.
   ========================================================================== */

:root {
  /* ----------------------------------------------------------------------
     THE WATER
     Aesthetic philosophy axis. Four stops of depth, top to bottom. The
     interval between them is the whole illusion: too even and it reads as a
     gradient swatch, too steep and the bottom of the page goes to ink and
     the schools disappear into it. Light falls off fast in real water, so
     the top two stops sit closer together than the bottom two.

     The surface stop is the one that got tuned rather than chosen. Its
     first draft was a full step lighter, and a light ray crossing it put
     the rail labels at 4.31:1, under the AA floor, on the brightest patch
     of a moving background. Darkening the surface stop fixed the whole
     scene at once, because every other paint is below it.
       ground ink on surface 7.07:1, mid 10.08:1, deep 13.11:1, abyss 16.24:1
     ---------------------------------------------------------------------- */
  --vo-water-surface: #125781; /* the lit top, just under the waterline */
  --vo-water-mid: #0a3f61;
  --vo-water-deep: #062c47;
  --vo-water-abyss: #03192b; /* the bottom of the frame */

  /* The sunbeams. One pale cool paint used by every beam; the beams differ
     in geometry and timing, never in color, which is what stops the scene
     from turning into a light show.

     THE OPACITY IS A STEP, NOT A TOTAL, and the difference matters. A beam
     with a hard left and right edge is a stripe, not a sunbeam. Each beam
     is therefore drawn as three quadrilaterals on a shared centreline, at
     full, 62% and 30% of its width, each painted at this one step opacity.
     They composite to 1 - (1 - 0.05)^3 = 0.1426 down the core and step down
     twice to nothing at the edges, which is a soft beam built out of three
     flat shapes and no blur filter.

     This is the value that decides whether text over water stays legible.
     At three steps of 0.05 the lightest paint the scene can produce is a
     beam core over the deep fish fill, #2e7095, and ground ink on it
     measures 4.94:1. Change this number, or the number of steps, and
     re-measure; there is nothing else holding the AA floor up. */
  --vo-ray: #cfeeff;
  --vo-ray-step: 0.05;

  /* The fish. Silhouettes, not portraits: one flat fill per school. A
     school near the surface sits DARKER than the water it swims in and a
     school below sits LIGHTER, which is how depth actually reads underwater
     and also means no school can ever be the lightest thing on screen.
     Which fill a school takes is decided by the water at its own depth, not
     by its rank in the stack; scene.css records the render where getting
     that backwards made seven fish invisible.
       ground ink over shallow 9.87:1, over deep 6.71:1, and over either
       with a beam core on top, 6.82:1 and 4.94:1
     Nothing depends on seeing a fish. They are texture. */
  --vo-fish-shallow: #0a4066;
  --vo-fish-deep: #135b83;

  /* Hovering a rail item deepens the water under it rather than lighting
     it. A light wash was the first instinct and it is the wrong one: it
     pushed ground ink to 4.11:1 and broke the floor at exactly the moment
     the reader was pointing at the word. Deepening moves contrast the right
     way (7.99:1 under the wash) and reads as the item sinking slightly.
     The components are --vo-water-abyss; keep them in sync. */
  --vo-rail-hover: rgba(3, 25, 43, 0.38);

  /* ----------------------------------------------------------------------
     SURFACES
     Aesthetic philosophy axis. The window is a lit page held underwater. It
     is opaque, and that is a decision rather than an oversight: frosted
     translucency is the obvious ocean move, and it makes every ratio in
     this file a function of whatever happens to be drifting behind the
     glass. An opaque window can be measured once. The collection already
     ships glassmorphism-theme for the other answer.

     Cool near-white rather than white, so the page reads as lit from the
     surface rather than pasted on.
     ---------------------------------------------------------------------- */
  --vo-surface: #f7fbfd; /* window body */
  --vo-chrome: #e6eff5; /* title bar */
  --vo-surface-muted: #dfeaf2; /* code blocks, table stripes, recessed panels */

  /* ----------------------------------------------------------------------
     INK
     Audience relationship axis. Deep blue-black rather than #000, so type
     inside the window belongs to the same world as the water outside it.
       ink on surface 15.63:1, chrome 13.97:1, surface-muted 13.32:1
       ink-muted on surface 6.35:1, chrome 5.67:1, surface-muted 5.41:1

     GROUND INK IS A SEPARATE TOKEN AND HAS NO MUTED SIBLING. Rail labels
     and anything else written straight onto the water use it at full
     strength only. A muted version would measure roughly 3:1 against the
     lightest water and there is nowhere on this theme it could safely be
     used, so it does not exist. If a re-skin lightens the water, this is
     the token to re-measure first.
       ground ink on the lightest possible scene paint 4.94:1
     ---------------------------------------------------------------------- */
  --vo-ink: #0b2233;
  --vo-ink-muted: #43616f;
  --vo-ground-ink: #eaf6ff;

  /* ----------------------------------------------------------------------
     THE ACCENT
     Sensory ambition axis. Exactly one accent and it is warm, because a
     blue accent on a blue ocean is not an accent. This deep coral is the
     only hue on the theme that is not blue, and it is spent on intent: the
     primary button, a link, the title bar's hairline. It lives on the light
     surfaces only; the water side has its own warm note below.
       accent on surface 5.60:1, chrome 5.01:1, surface-muted 4.77:1
       white on accent 5.83:1
     ---------------------------------------------------------------------- */
  --vo-accent: #b8371d;
  --vo-accent-ink: #ffffff;

  /* ----------------------------------------------------------------------
     DESTRUCTIVE
     Tone register axis. One red, for the action that deletes something and
     for invalid input.

     NAMED RISK, because it is real and this is where it belongs: this
     theme's accent is also warm, and two warm reds is one more than a
     palette wants. They are separated by hue and by weight, the accent
     orange-red and the destructive crimson, and by rule they never appear
     adjacent in the same role. If you re-skin and the accent moves cooler,
     this token gets easier, not harder.
       destructive on surface 7.59:1, white on destructive 7.90:1
     ---------------------------------------------------------------------- */
  --vo-destructive: #9e1b32;
  --vo-destructive-ink: #ffffff;

  /* ----------------------------------------------------------------------
     FLAT SEMANTIC FILLS
     Aesthetic philosophy axis. Pale enough to take full-strength ink, so
     meaning lives in the hue and legibility never depends on it. Ink on
     every fill clears AA with room:
       success 12.70:1, info 12.38:1, warning 13.15:1, danger 12.01:1
     ---------------------------------------------------------------------- */
  --vo-fill-success: #c7ecd6;
  --vo-fill-info: #cfe3f7;
  --vo-fill-warning: #f8e6b4;
  --vo-fill-danger: #f8d5d8;

  /* ----------------------------------------------------------------------
     BORDER
     Aesthetic philosophy axis. Two weights. The hairline (1.47:1 on
     surface) is tidiness only and carries no information. The strong
     border is any control boundary that has to be findable on its own:
     3.73:1 on surface, 3.34:1 on chrome, 3.18:1 on surface-muted, clearing
     the 3:1 UI floor on all three.

     Neither is what separates the window from the water. That job belongs
     to the window's own surface, which measures 5.22:1 against the lightest
     paint the scene can produce; a border strong enough to outline a light
     window on dark water would have to be lighter than the window, which is
     backwards. The window is legible as a shape because it is a bright
     rectangle in deep water, and that is measured rather than assumed.
     ---------------------------------------------------------------------- */
  --vo-border-width: 1px;
  --vo-border: #c2d4de; /* hairline, decorative separation */
  --vo-border-strong: #6b8593; /* control boundaries */

  /* ----------------------------------------------------------------------
     SHADOW
     Sensory ambition axis. Deep-water shadow: the components (3, 25, 43)
     are --vo-water-abyss rather than the ink, because on this theme a
     shadow is the water darkening under an object, not a light-theme grey.
     Keep them in sync if you move the abyss.
     ---------------------------------------------------------------------- */
  --vo-shadow-sm: 0 1px 2px rgba(3, 25, 43, 0.16);
  --vo-shadow-raised: 0 1px 2px rgba(3, 25, 43, 0.14),
    0 4px 12px -2px rgba(3, 25, 43, 0.2);
  --vo-shadow-window: 0 2px 4px rgba(3, 25, 43, 0.22),
    0 18px 44px -10px rgba(3, 25, 43, 0.5);

  /* ----------------------------------------------------------------------
     RADIUS
     Audience relationship axis. One step softer than the fleet's desktop
     pilot at the window corner, because this window is a single object a
     reader looks at for the whole visit rather than one of a pile.
     ---------------------------------------------------------------------- */
  --vo-radius-tight: 4px; /* badges, tags, keyboard hints */
  --vo-radius: 8px; /* buttons, inputs, rail items */
  --vo-radius-window: 14px; /* the window and the mobile menu panel */
  --vo-radius-pill: 999px;

  /* ----------------------------------------------------------------------
     TYPE
     Tone register axis. System fonts, no webfont, no network request. The
     scale runs one step larger at the top than the desktop pilot's, because
     this shell's window is the whole site rather than a card in a pile, and
     a home page hero inside it has a landing page's job to do.
     ---------------------------------------------------------------------- */
  --vo-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --vo-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  --vo-weight-body: 400;
  --vo-weight-medium: 500;
  --vo-weight-bold: 700;
  --vo-weight-display: 760;

  --vo-text-display: 3.25rem; /* 52px */
  --vo-text-h1: 2.25rem; /* 36px */
  --vo-text-h2: 1.625rem; /* 26px */
  --vo-text-h3: 1.25rem; /* 20px */
  --vo-text-lead: 1.125rem; /* 18px */
  --vo-text-body: 1rem; /* 16px, the floor for form inputs on iOS */
  --vo-text-sm: 0.875rem; /* 14px, the floor for any body content */
  --vo-text-xs: 0.75rem; /* 12px, labels, badges, rail captions */

  --vo-leading-tight: 1.08;
  --vo-leading-snug: 1.3;
  --vo-leading-body: 1.65;

  --vo-tracking-tight: -0.018em;
  --vo-tracking-wide: 0.06em;

  /* ----------------------------------------------------------------------
     SPACE
     Aesthetic philosophy axis. A fixed scale. The measure is the prose
     width inside the window; the window itself is sized in the shell
     geometry group below, and the two are deliberately different numbers.
     ---------------------------------------------------------------------- */
  --vo-space-1: 4px;
  --vo-space-2: 8px;
  --vo-space-3: 12px;
  --vo-space-4: 16px;
  --vo-space-6: 24px;
  --vo-space-8: 32px;
  --vo-space-12: 48px;
  --vo-space-16: 64px;

  --vo-measure: 68ch;

  /* ----------------------------------------------------------------------
     MOTION: THE INTERFACE
     Sensory ambition axis. The interface has one motion vocabulary and it is
     a settle: opacity, over --vo-duration, from the single `vo-settle`
     keyframe in shell.css. It is spent at three moments and no others — a
     content swap, the mobile menu panel opening, and the window returning
     from a clear desk. Three moments, one keyframe, no easing zoo.

     This comment used to say "the interface animates twice and no more",
     which was a count of moments written as if it were a count of
     animations, and the window's return made it wrong. The claim worth
     making is the one above: not how many times, but that there is only ever
     one thing happening. Everything the reader came to look at is in the
     next group.
     ---------------------------------------------------------------------- */
  --vo-duration: 180ms;
  --vo-ease: cubic-bezier(0.2, 0, 0, 1);
  --vo-swap-duration: 160ms;

  /* ----------------------------------------------------------------------
     MOTION: THE WATER
     Sensory ambition axis, and the reason this repo exists. Every value
     here is slow on purpose. The fastest thing in the scene takes most of a
     minute to cross the frame, which is the difference between a seascape
     and a screensaver: at these speeds nothing ever demands to be watched,
     and a reader who does watch is never waiting for a loop to come round.

     Three schools at three depths, three speeds, two directions. The
     spread is what produces parallax; if these three numbers were close
     together the schools would read as one layer with gaps in it.

     UNDER prefers-reduced-motion THE BLOCK AT THE BOTTOM OF THIS FILE SETS
     ALL FOUR TO 0s. That is not a pause. Every animated shape in scene.css
     is authored so that its UNANIMATED position is a composed still life,
     with the schools placed where they belong in a picture rather than
     wherever the clock happened to stop them. Reduced motion gets a
     photograph of the ocean, and it is also the state every capture in this
     repo is taken in.
     ---------------------------------------------------------------------- */
  --vo-drift-near: 54s; /* the near school, largest and quickest */
  --vo-drift-mid: 82s;
  --vo-drift-far: 124s; /* the far school, smallest and slowest */
  --vo-ray-shift: 28s; /* the sunbeams' sway, slowest of all */

  /* How far the sunbeams lean at the ends of their sway. A percentage of
     the view box, so it scales with the viewport instead of needing a
     breakpoint. There is deliberately NO matching token for how far a
     school travels: that distance is structural rather than a design value,
     because it has to equal the spacing between the two copies of each
     shoal in the markup or the loop visibly jumps. scene.css says so at the
     keyframes, and a token there would be an invitation to break it. */
  --vo-ray-sway: 2.5%;

  /* ----------------------------------------------------------------------
     FOCUS
     Audience relationship axis. THE RING IS TWO COLORS, AND IT HAS TO BE.
     A single-color focus ring is a promise about the background behind it,
     and this theme has no such background: the same rail item sits over lit
     surface water at the top of the screen and near-black abyss at the
     bottom, and anything that clears 3:1 against one of those fails the
     other. So the ring is a warm light band with a deep halo drawn tight
     around it, and the guarantee is that at least one of the two clears the
     3:1 UI floor against every paint in the theme. Measured, over every
     backdrop that exists here:

       backdrop              ring    halo
       window surface        1.25    16.79
       window chrome         1.12    15.01
       surface-muted         1.06    14.31
       water, surface stop   5.97     2.25
       water, mid stop       8.51     1.58
       water, deep stop      5.66     2.37
       water, abyss stop    13.71     1.02
       lightest scene paint  4.17     3.22

     Eight backdrops, no column without a pass, and the two colors measure
     13.44:1 against each other so the band never reads as one thick edge.

     The ring color is also the only warm note on the water side of the
     theme, which is deliberate: it is the same warmth as the sunbeams, so
     focus reads as light finding the thing you are pointing at.
     ---------------------------------------------------------------------- */
  --vo-ring: #ffdda6;
  --vo-ring-halo: #041b2e;
  --vo-ring-width: 3px;
  --vo-ring-offset: 2px;

  /* ----------------------------------------------------------------------
     SHELL GEOMETRY
     The measurements of the machine. shell/shell.css draws the window and
     both rails entirely from these.

     The window width is the number this shell lives or dies by, and it is
     the one place where the content and the picture are in direct
     competition. Too narrow and a pricing table cannot breathe; too wide
     and the water stops being visible on a laptop, which is the whole
     composition. 840px against a 1280px viewport leaves a 220px channel of
     open water down each side, which is what the rails need with room to
     spare and what the scene needs to still be a scene.

     The rail zone is what the layout reserves on each side. It is a token
     because the window's width is computed from it, so the two can never
     drift apart and crowd each other.
     ---------------------------------------------------------------------- */
  --vo-titlebar-height: 44px;
  --vo-control-size: 32px; /* title bar tray buttons */
  --vo-window-width: 840px;
  --vo-window-inset: 48px; /* clearance above and below the window */

  /* How much water stays visible above the window on a narrow screen. This
     token exists because the matrix caught its absence: with the window
     truly full-bleed at 390, the ocean, calm and prefers-contrast cells all
     hashed identically, which is the pixel-level way of discovering that
     none of the ground was on screen at all. A theme whose ground is the
     product cannot let a phone hide the product. */
  --vo-window-band: 64px;

  /* Where the launcher stands when the window is closed. It is shell geometry
     rather than spacing because it is a clearance from two screen edges, and
     it has to stay well clear of the 5px the focus ring needs outside the
     control (--vo-ring-width plus --vo-ring-offset) at the one corner of the
     screen this theme puts a control in. Class decision 36's third mechanic,
     at the only edge that gains chrome in the desk-clear state. */
  --vo-launch-inset: 24px;

  --vo-rail-zone: 116px; /* reserved on each side for a rail */
  --vo-rail-icon: 40px; /* the glyph box on a rail item */
  --vo-rail-cell: 88px; /* full rail item including its caption */
  --vo-rail-gap: 4px;
  --vo-menu-width: 320px; /* the mobile menu panel */

  /* Layering. The scene is under everything, the window sits on it, the
     rails are chrome above the window, the launcher above the rails, the
     mobile menu above that, and the skip link above all of it.

     THE LAUNCHER'S LAYER IS NOT DECORATION. At 1024 and up it stands in the
     top of the left rail's column, and a rail is a full-height fixed element,
     so the two overlap by construction rather than by accident. Sharing a
     layer with the rails left the launcher painted under one and, because
     hit-testing follows the same order, un-clickable across its first
     ninety-two pixels — the mark and the first half of the word. A walk
     caught it; nothing about the screenshot showed it. */
  --vo-z-scene: 0;
  --vo-z-window: 10;
  --vo-z-rail: 20;
  --vo-z-launch: 30;
  --vo-z-menu: 40;
  --vo-z-skip: 50;
}

/* Anyone who has asked their operating system to stop animating gets the
   composed still life rather than a paused loop, and the interface stops
   crossfading. Zeroing the durations is the whole mechanism: every animated
   shape in scene.css is authored at its resting position, so a duration of
   zero is not an absence of motion, it is the picture. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --vo-duration: 1ms;
    --vo-swap-duration: 1ms;
    --vo-drift-near: 0s;
    --vo-drift-mid: 0s;
    --vo-drift-far: 0s;
    --vo-ray-shift: 0s;
  }
}
