/* ─────────────────────────────────────────────────────────────────────────
   surfaces/_shell/shell.css — the palette and the furniture, for every
   surface in the network.

   Created 2026-08-08, Wave 1C. This file is the reason a new surface costs a
   manifest and a page (blackbox I347): a surface writes its own content and
   inherits every colour, every type step and every piece of chrome from here.

   THE PALETTES ARE NOT NEW AND MUST NOT BECOME NEW. They are lifted verbatim
   from product/app/app.css, where each one was measured pair-by-pair by
   check_css.py's contrast matrix, and where several of the values carry a
   correction that was made against a real measured failure (Sun and Jupiter on
   the lit pill, --moon-deep having no day value at all). Re-picking them here
   would throw all of that away and re-earn it. So: SKIN NUMBERS MEAN THE SAME
   THING IN BOTH CODEBASES. Skin 3 is Porcelain in Beyond and Porcelain here.
   If a palette changes in one place it is copied to the other by hand, on
   purpose, and never diverged silently.

   WHAT IS DELIBERATELY NOT HERE:

     · NO AD SLOT, and there is no `--ad-*` token, no `.ad` class and no key in
       surface.json to switch one on. Blackbox I337 is a standing law: never on
       a daily view, ever. A slot in the shell's default chrome is how "never
       on the daily view" quietly becomes "on every page including the daily
       one" — the slot exists, so somebody fills it. When ads are switched on
       (100k monthly pageviews, not before) they are built into the SPECIFIC
       page that carries them, below the answer, in this skin's own type. That
       is a page's decision and it is never the shell's default.

     · NO STARFIELD, NO NEBULA, NO AURORA. Those are Beyond's, they are drawn
       from data, and engine/README.md is explicit that the engine does not
       draw. A surface that wants a sky mounts one; the shell does not assume
       every surface is about the sky.

     · NO WORDMARK TYPE. The webfont is Beyond's brand and costs ~15 KB. A
       utility surface is a system-font page until somebody decides otherwise.
   ───────────────────────────────────────────────────────────────────────── */

/* ── THE PALETTE IS TYPED, WHICH IS WHAT LETS IT MOVE ──────────────────────
   Straight from app.css and worth the twelve lines here too. An unregistered
   custom property is a STRING to the cascade: `--panel:#10141C` and
   `--panel:#FFFFFF` are unrelated tokens that happen to look like colours, so
   there is no midpoint and a skin change is a hard cut no matter what
   transition is declared. @property states the type, the browser parses to a
   colour at computed-value time, and the change can dissolve.

   The initial-value has to be a literal — it is resolved once, globally,
   before any element exists, so it cannot contain var() or color-mix(). These
   mirror Midnight below; nothing reads them, because :root always declares a
   real value. They exist because the syntax requires them.

   check_css.py does not see these and that is correct rather than lucky: its
   rules() walks at-rules looking for nested RULES, and an @property body holds
   only declarations. */
@property --ink      {syntax:"<color>";inherits:true;initial-value:#0A0D12;}
@property --panel    {syntax:"<color>";inherits:true;initial-value:#10141C;}
@property --panel2   {syntax:"<color>";inherits:true;initial-value:#141A24;}
@property --line     {syntax:"<color>";inherits:true;initial-value:#1E2530;}
@property --line2    {syntax:"<color>";inherits:true;initial-value:#2A3442;}
@property --text     {syntax:"<color>";inherits:true;initial-value:#DCE3EC;}
@property --muted    {syntax:"<color>";inherits:true;initial-value:#96A2B2;}
@property --faint    {syntax:"<color>";inherits:true;initial-value:#7A8698;}
@property --moon     {syntax:"<color>";inherits:true;initial-value:#D6E6F7;}
@property --moon-deep{syntax:"<color>";inherits:true;initial-value:#9FB8D4;}
@property --amber    {syntax:"<color>";inherits:true;initial-value:#E0A85C;}
@property --green    {syntax:"<color>";inherits:true;initial-value:#84BE8B;}
@property --rose     {syntax:"<color>";inherits:true;initial-value:#D194A0;}
@property --bg       {syntax:"<color>";inherits:true;initial-value:#05070A;}
@property --glow     {syntax:"<color>";inherits:true;initial-value:#121B29;}

/* ── 1 · MIDNIGHT — the default, and the :root palette ─────────────────────
   Indigo deep-field. This is the palette every dark skin inherits from by
   declaring nothing, which is why a stop that only wants a different FIELD
   costs no colour at all. */
:root{
  --ink:#0A0D12; --panel:#10141C; --panel2:#141A24; --line:#1E2530; --line2:#2A3442;
  --text:#DCE3EC; --muted:#96A2B2; --faint:#7A8698;
  --moon:#D6E6F7; --moon-deep:#9FB8D4;
  --amber:#E0A85C; --green:#84BE8B; --rose:#D194A0;
  --bg:#05070A; --glow:#121B29;
  color-scheme:dark;

  /* Type. System faces only — see the header. The scale is 1.25 and it is
     fixed px rather than fluid, for the reason app.css spells out at length:
     the column is capped, so type keyed to the viewport would grow while its
     container did not. A surface that later earns a real wide layout comes
     back here; until then fixed is correct rather than merely untouched. */
  --mono:ui-monospace,"SF Mono",SFMono-Regular,Menlo,Consolas,monospace;
  --sans:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --serif:"Iowan Old Style","Palatino Linotype",Palatino,"Book Antiqua",Georgia,serif;
  --t-xs:11px; --t-sm:13px; --t-md:15px; --t-lg:19px; --t-xl:24px; --t-2xl:30px;

  /* Motion, as three numbers in one place. Anything hard-coded elsewhere is a
     bug: it sits outside this file and drifts away from whatever these
     settle on. skin.js READS --mo-skin at runtime rather than keeping a copy,
     so the dissolve and the class that cleans up after it can never
     disagree — the exact trap app.css records. */
  --mo-skin:420ms;      /* palette dissolve, skin to skin */
  --mo-swap:200ms;      /* soft navigation, page swapping */
  --mo-sheet:220ms;     /* the install sheet rising      */

  /* Layout. One number decides the measure of every surface in the network. */
  --measure:min(620px,100% - 32px);
  --radius:10px;
}

/* ── THE DAY BASE ──────────────────────────────────────────────────────────
   Every colour declared for night needs a value here, and check_css.py check
   2(a) fails the build if one is missing. That check exists because
   --moon-deep once had no day value and six rules painted night's pale blue
   onto paper at 1.6:1 for several releases.

   The values are Porcelain's. A light skin overrides them again in its own
   block; this exists so that a surface which only ever sets data-theme="day"
   — the Journal does exactly that in Beyond — still gets a complete palette
   rather than an inherited half of one. */
:root[data-theme="day"]{
  --ink:#FCFDFE; --panel:#FFFFFF; --panel2:#F1F4F8; --line:#E1E7EE; --line2:#CBD4DE;
  --text:#131A22; --muted:#3B4655; --faint:#57626F;
  --moon:#25415E; --moon-deep:#33536F;
  --amber:#8A5A12; --green:#2F6B45; --rose:#94414F;
  --bg:#EFF3F8; --glow:#FFFFFF;
  color-scheme:light;
}

/* ── THE FOUR SKINS ────────────────────────────────────────────────────────
   ONE BLOCK PER SKIN, NEVER GROUPED, and this is not house style. check_css's
   rules() yields only the LAST selector of a comma-separated group, so
   `[data-skin="1"],[data-skin="5"]{…}` ships skin 1 unmeasured. That trap has
   already been paid for twice in app.css (I32, and again on the new stops).
   Every skin gets its own block, every time.

   --skin-base and --skin-name are how check_css DISCOVERS the skins rather
   than being handed a hard-coded list that drifts the first time somebody
   adds a fifth. Add one and it is measured automatically; there is nothing to
   remember. */

/* 1 · Midnight — the original. Declares no tones: :root above IS its palette,
   so this block exists purely to name it and to be discoverable. */
:root[data-skin="1"]{--skin-base:dark;--skin-name:midnight;}

/* 3 · Porcelain — cool, crisp, clinical. The one that looks like software,
   and the light default: a device that prefers light lands here on the first
   visit. Numbered 3 because it is 3 in Beyond. */
:root[data-skin="3"]{--skin-base:light;--skin-name:porcelain;
  --ink:#FCFDFE; --panel:#FFFFFF; --panel2:#F1F4F8; --line:#E1E7EE; --line2:#CBD4DE;
  --text:#131A22; --muted:#3B4655; --faint:#57626F;
  --moon:#25415E; --moon-deep:#33536F;
  --amber:#8A5A12; --green:#2F6B45; --rose:#94414F;
  --bg:#EFF3F8; --glow:#FFFFFF;
  color-scheme:light;}

/* 5 · Abyss — Midnight pushed deeper and bluer: the grounds lose their last
   warmth and the ink gains a trace of it back, so text on the deepest surface
   still separates. */
:root[data-skin="5"]{--skin-base:dark;--skin-name:abyss;
  --ink:#060910; --panel:#0B1120; --panel2:#101828; --line:#1A2438; --line2:#26344C;
  --text:#DAE2F0; --muted:#93A1BC; --faint:#7683A0;
  --moon:#CBDBF2; --moon-deep:#93AAD0;
  --amber:#DCA65E; --green:#7FBA8C; --rose:#CC93A4;
  --bg:#03050A; --glow:#0D1526;
  color-scheme:dark;}

/* 7 · Plain — pure black, pure white, three signal colours and nothing else.
   The lines are deliberately heavy: an 8-bit look is carried by its edges,
   and a hairline at Midnight's weight would read as the same page with the
   colour drained rather than as a different one.

   IT IS ALSO THE FLOOR. Plain is the stop with no gradients, no translucency
   and no backdrop-filter, so it is what the shell falls back to when
   something in the atmospheric layer misbehaves on a device — the same job
   `Light` does for Beyond's Rive layer, which is where the idea comes from.
   A floor the reader can reach is worth more than one only we can deploy. */
:root[data-skin="7"]{--skin-base:dark;--skin-name:plain;
  --ink:#000000; --panel:#000000; --panel2:#0B0B0B; --line:#3D3D3D; --line2:#7A7A7A;
  --text:#FFFFFF; --muted:#D4D4D4; --faint:#AEAEAE;
  --moon:#FFFFFF; --moon-deep:#CFCFCF;
  --amber:#FFC400; --green:#3CE07C; --rose:#FF8FB4;
  --bg:#000000; --glow:#0F0F0F;
  color-scheme:dark;}

/* The half-second the typed palette bought. Added by skin.js for exactly one
   dissolve and taken off again, so nothing else in the page is paying a
   transition cost for a control most readers touch once. */
:root.skinning,:root.skinning *{
  transition:background-color var(--mo-skin) ease,
             background-image var(--mo-skin) ease,
             color var(--mo-skin) ease,
             border-color var(--mo-skin) ease !important;}
@media (prefers-reduced-motion:reduce){
  :root.skinning,:root.skinning *{transition:none !important;}}

/* Plain paints flat, everywhere. Declared once here rather than as an
   exception inside each rule below. */
:root[data-skin="7"] *{backdrop-filter:none !important;}

/* ── the reset, and the page ───────────────────────────────────────────────
   `hidden` is enforced by the UA sheet at (0,0,1), so any class that sets
   display outranks it — which in Beyond kept a sign-in button on screen for
   signed-in users no matter how often the code set the attribute. Settle it
   once, globally, rather than patching each offender. */
[hidden]{display:none !important;}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
html{-webkit-text-size-adjust:100%;}
html,body{margin:0;background:var(--bg);color:var(--text);font-family:var(--sans);}
body{min-height:100dvh;display:flex;flex-direction:column;align-items:center;
  font-size:var(--t-md);line-height:1.6;
  background:radial-gradient(ellipse 90% 40% at 50% -5%,var(--glow) 0%,var(--bg) 55%);}
:root[data-skin="7"] body{background:var(--bg);}

/* 100dvh is iOS 15.4+. The fallback keeps a short page from collapsing on
   anything older; nothing here is load-bearing on the difference. */
@supports not (height:100dvh){ body{min-height:100vh;} }

main{width:var(--measure);flex:1 0 auto;padding:8px 0 40px;}
a{color:var(--moon);text-underline-offset:2px;}
a:hover{color:var(--moon-deep);}

/* ── the header ────────────────────────────────────────────────────────────
   Deliberately thin. A single-purpose utility that opens with a navigation
   bar has already told the reader it is a suite, and it is not one. The
   surface's name, and the skin control. Everything else belongs on the page. */
.sh-head{width:var(--measure);display:flex;align-items:center;gap:12px;
  padding:14px 0 10px;}
.sh-name{font-family:var(--mono);font-size:var(--t-sm);letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted);text-decoration:none;
  margin-right:auto;}
.sh-name:hover{color:var(--text);}
.sh-name b{color:var(--text);font-weight:600;}

/* ── controls ──────────────────────────────────────────────────────────────
   The skin button carries its NUMBER, on purpose and copied from Beyond: a
   palette name nobody has seen before is not something a reader can report
   back, and "I like 3" is. */
.sh-btn{font-family:var(--mono);font-size:var(--t-xs);letter-spacing:.1em;
  display:inline-flex;align-items:center;gap:6px;
  padding:7px 12px;border-radius:999px;cursor:pointer;
  border:1px solid var(--line2);
  background:color-mix(in srgb,var(--panel) 82%,transparent);
  color:var(--text);backdrop-filter:blur(10px);}
.sh-btn:hover{border-color:var(--moon-deep);}
.sh-btn b{font-weight:600;}
.sh-btn[disabled]{opacity:.5;cursor:default;}

.sh-btn.primary{background:var(--moon);color:var(--ink);border-color:var(--moon);}
.sh-btn.primary:hover{background:var(--moon-deep);color:var(--ink);}

/* The name of the skin, said once and briefly on every change. */
.sh-skinname{position:fixed;left:50%;bottom:78px;z-index:60;pointer-events:none;
  transform:translateX(-50%) translateY(6px);opacity:0;
  font-family:var(--mono);font-size:var(--t-xs);letter-spacing:.14em;
  text-transform:uppercase;color:var(--text);
  background:color-mix(in srgb,var(--panel) 92%,transparent);
  border:1px solid var(--line2);border-radius:999px;padding:7px 15px;
  backdrop-filter:blur(10px);}
.sh-skinname.show{animation:sh-flash 1.9s ease forwards;}
@keyframes sh-flash{
  0%{opacity:0;transform:translateX(-50%) translateY(6px);}
  14%{opacity:1;transform:translateX(-50%) translateY(0);}
  72%{opacity:1;transform:translateX(-50%) translateY(0);}
  100%{opacity:0;transform:translateX(-50%) translateY(-4px);}}
@media (prefers-reduced-motion:reduce){
  .sh-skinname.show{animation:none;opacity:1;transform:translateX(-50%);}}

/* ── the primitives a page is allowed to assume ────────────────────────────
   Small on purpose. Every class here is one a second surface will also want;
   anything only one surface needs is that surface's stylesheet, not this one.
   The test is the same as engine/README.md's: something one surface needs and
   no other could is a surface module wearing a disguise. */
.sh-card{background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius);padding:16px 18px;margin:0 0 14px;}
.sh-card > :first-child{margin-top:0;}
.sh-card > :last-child{margin-bottom:0;}

.sh-eyebrow{font-family:var(--mono);font-size:var(--t-xs);letter-spacing:.2em;
  text-transform:uppercase;color:var(--faint);margin:0 0 8px;}
.sh-lede{font-size:var(--t-lg);line-height:1.45;color:var(--text);margin:0 0 14px;}
.sh-note{font-size:var(--t-sm);color:var(--muted);margin:0;}

h1{font-size:var(--t-2xl);line-height:1.2;margin:18px 0 10px;font-weight:600;}
h2{font-size:var(--t-xl);line-height:1.25;margin:26px 0 8px;font-weight:600;}
h3{font-size:var(--t-lg);line-height:1.3;margin:20px 0 6px;font-weight:600;}
code,kbd{font-family:var(--mono);font-size:.92em;}

/* ── THE LEGAL DOCUMENTS (I520) ────────────────────────────────────────────
   `/privacy` and `/terms` are built into every surface by legal.py from one
   markdown source, and the markup they arrive as is whatever that document
   happens to use — headings, paragraphs, lists, a table, a rule. So this is
   the one place in the shell that styles bare tags inside a container rather
   than offering classes: there is no author to hand a class list to.

   It is a READING style, not a small-print style. These two documents are the
   ones a store reviewer opens, and a privacy policy set in the quietest tone
   available says the publisher would rather it were not read. Body text is
   --text at the page's own size; only the table header and the effective-date
   line step back. */
.sh-prose{max-width:100%;}
.sh-prose > :first-child{margin-top:0;}
.sh-prose > :last-child{margin-bottom:0;}
.sh-prose p{margin:0 0 14px;}
.sh-prose ul{margin:0 0 14px;padding-left:22px;}
.sh-prose li{margin:0 0 6px;}
.sh-prose li:last-child{margin-bottom:0;}
.sh-prose hr{border:0;border-top:1px solid var(--line);margin:30px 0 24px;}
.sh-prose blockquote{margin:0 0 14px;padding:0 0 0 14px;
  border-left:2px solid var(--line2);}
.sh-prose blockquote p:last-child{margin-bottom:0;}

/* A legal document's tables are two or three columns of short phrases, and on
   a phone they are the one thing here that cannot reflow. Scrolling the table
   is the honest failure; scrolling the page sideways is not. */
.sh-prose table{width:100%;border-collapse:collapse;margin:0 0 16px;
  font-size:var(--t-sm);display:block;overflow-x:auto;}
.sh-prose th,.sh-prose td{text-align:left;vertical-align:top;padding:8px 12px 8px 0;
  border-bottom:1px solid var(--line);}
.sh-prose th{color:var(--muted);font-weight:600;font-size:var(--t-xs);
  letter-spacing:.06em;text-transform:uppercase;
  border-bottom-color:var(--line2);}

/* ── THE METHOD LINE ───────────────────────────────────────────────────────
   Not decoration and not a footnote. §4.2 of EXECUTION - The Roadmap.md makes
   a declared method part of the definition of done for every surface:
   ayanamsa, sunrise definition, siddhanta, in one line, on the page. Nobody
   else in this market does it, which is the whole reason it is a class in the
   shell rather than a paragraph somebody remembers to write.

   It is styled to be read, not hidden: --muted, not --faint. A method
   declaration set in the quietest tone on the page is a disclaimer. */
.sh-method{font-family:var(--mono);font-size:var(--t-xs);line-height:1.7;
  letter-spacing:.04em;color:var(--muted);
  border-top:1px solid var(--line);padding:12px 0 0;margin:22px 0 0;}
.sh-method b{color:var(--text);font-weight:600;}

/* ── the cross-property footer (I344) ──────────────────────────────────────
   On the open web there is no policy against linking your own sites, so this
   is free and it runs from day one. It is a strip, not a menu: the reader is
   here for one thing, and the other properties are a discovery, not a
   navigation choice they have to make first.

   Rendered by footer.js from network.json, so a new property is announced in
   ONE file and appears in the footer of everything already deployed on the
   next build. */
.sh-foot{width:100%;border-top:1px solid var(--line);margin-top:auto;
  background:var(--panel);}
.sh-foot-in{width:var(--measure);margin:0 auto;padding:20px 0 28px;
  display:flex;flex-direction:column;gap:14px;}
.sh-net{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:0;padding:0;}
.sh-net a{display:inline-flex;flex-direction:column;gap:2px;
  padding:9px 13px;border:1px solid var(--line);border-radius:var(--radius);
  text-decoration:none;background:var(--panel2);color:var(--text);}
.sh-net a:hover{border-color:var(--moon-deep);color:var(--text);}
.sh-net .t{font-size:var(--t-sm);font-weight:600;}
.sh-net .d{font-size:var(--t-xs);color:var(--muted);}
.sh-net .here{border-color:var(--line2);opacity:.6;pointer-events:none;}
.sh-net .soon .d::after{content:" · soon";color:var(--faint);}
.sh-fine{font-size:var(--t-xs);line-height:1.7;color:var(--faint);margin:0;}
.sh-fine a{color:var(--muted);}

/* ── the install prompt ────────────────────────────────────────────────────
   Two entirely different mechanisms behind one affordance — see install.js.
   The sheet is the iOS one, and it is instructions rather than a button,
   because on iOS there is no event to hang a button on. */
.sh-sheet{position:fixed;inset:0;z-index:80;display:flex;align-items:flex-end;
  justify-content:center;
  background:color-mix(in srgb,var(--ink) 62%,transparent);}
.sh-sheet[hidden]{display:none !important;}
.sh-sheet-in{width:min(520px,100%);background:var(--panel);color:var(--text);
  border-top:1px solid var(--line2);
  border-radius:var(--radius) var(--radius) 0 0;padding:20px 20px 28px;
  animation:sh-rise var(--mo-sheet) cubic-bezier(.2,.8,.3,1) both;}
@keyframes sh-rise{from{transform:translateY(14px);opacity:0;}
                   to{transform:none;opacity:1;}}
@media (prefers-reduced-motion:reduce){ .sh-sheet-in{animation:none;} }
.sh-steps{margin:12px 0 0;padding:0 0 0 20px;font-size:var(--t-sm);
  line-height:1.75;color:var(--muted);}
.sh-steps b{color:var(--text);}
.sh-sheet-act{display:flex;gap:10px;margin-top:18px;}

/* ── soft navigation ───────────────────────────────────────────────────────
   The page swap in router.js. Kept to opacity — a transform on <main> during
   a swap fights the browser's own scroll restoration, and losing the scroll
   position is a worse bug than a plain fade is a missed opportunity. */
main.sh-leaving{opacity:0;transition:opacity var(--mo-swap) ease;}
@media (prefers-reduced-motion:reduce){ main.sh-leaving{transition:none;} }

/* ── focus, and it is visible ──────────────────────────────────────────────
   One outline, in a palette tone, on everything focusable. A utility used by
   somebody on a keyboard is a utility used by somebody who will notice. */
:focus-visible{outline:2px solid var(--moon);outline-offset:2px;border-radius:3px;}
